From 0d74bc7ee249ea82f88d65a6e7de387d400eb9c8 Mon Sep 17 00:00:00 2001 From: David Bernard Date: Sun, 21 Jan 2024 23:02:15 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20enforce=20mutation=20to=20only=20cr?= =?UTF-8?q?eate=20coherente=20cdevents=20(type=20match=20subject.content)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hide context - provide accessor and mutator to restrict access Signed-off-by: David Bernard --- README.md | 40 +-- cdevents-sdk/examples/pipelinerun_finished.rs | 41 +-- cdevents-sdk/src/cdevent.rs | 104 +++++- cdevents-sdk/src/cloudevents.rs | 45 +-- cdevents-sdk/src/context.rs | 14 +- cdevents-sdk/src/generated/mod.rs | 327 +++++++++++++++--- .../src/generated/testcaserun_finished.rs | 2 +- .../src/generated/testcaserun_queued.rs | 4 +- .../src/generated/testcaserun_started.rs | 4 +- .../src/generated/testsuiterun_queued.rs | 2 +- .../src/generated/testsuiterun_started.rs | 2 +- cdevents-sdk/src/lib.rs | 2 +- cdevents-sdk/src/subject.rs | 56 ++- generator/src/main.rs | 2 +- generator/templates/mod.hbs | 27 +- 15 files changed, 526 insertions(+), 146 deletions(-) diff --git a/README.md b/README.md index e359630..5dc967b 100644 --- a/README.md +++ b/README.md @@ -18,33 +18,23 @@ To send a CDEvent as CloudEvent: // from examples/pipelinerun_finished.rs use std::error::Error; -use cdevents_sdk::{CDEvent, Context, Subject, pipelinerun_finished, Content}; +use cdevents_sdk::{CDEvent, Subject, pipelinerun_finished, Content}; use cloudevents::{Event, AttributesReader}; -use time::OffsetDateTime; fn main() -> Result<(), Box> { - let cdevent = CDEvent { - context: Context { - version: "0.3.0".to_string(), - id: "271069a8-fc18-44f1-b38f-9d70a1695819".to_string(), - r#type: "dev.cdevents.pipelinerun.finished.0.1.1".to_string(), - source: "/event/source/123".try_into()?, - timestamp: OffsetDateTime::now_utc(), - }, - subject: Subject { - id: "/dev/pipeline/run/1".to_string(), - source: Some("https://dev.pipeline.run/source".try_into()?), - r#type: "build".to_string(), - content: Content::PipelinerunFinished(pipelinerun_finished::Content{ - errors: Some("pipelineErrors".into()), - outcome: Some("success".into()), - pipeline_name: Some("testPipeline".into()), - url: Some("https://dev.pipeline.run/source".into()) - }) - }, - custom_data: None, - custom_data_content_type: None, - }; + let cdevent = CDEvent::from( + Subject::from(pipelinerun_finished::Content{ + errors: Some("pipelineErrors".into()), + outcome: Some("success".into()), + pipeline_name: Some("testPipeline".into()), + url: Some("https://dev.pipeline.run/url".into()) + }) + .with_id("/dev/pipeline/run/1") + .with_source("https://dev.pipeline.run/source".try_into()?) + ) + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819") + .with_source("https://dev.cdevents".try_into()?) + ; let cdevent_expected = cdevent.clone(); @@ -62,7 +52,7 @@ fn main() -> Result<(), Box> { let cloudevent_received: Event = cloudevent.clone(); let cdevent_extracted: CDEvent = cloudevent_received.try_into()?; - assert_eq!(cloudevent.id(), cdevent_extracted.context.id); + assert_eq!(cloudevent.id(), cdevent_extracted.id()); assert_eq!(cdevent_expected, cdevent_extracted); Ok(()) } diff --git a/cdevents-sdk/examples/pipelinerun_finished.rs b/cdevents-sdk/examples/pipelinerun_finished.rs index f017b57..4bfdef6 100644 --- a/cdevents-sdk/examples/pipelinerun_finished.rs +++ b/cdevents-sdk/examples/pipelinerun_finished.rs @@ -1,32 +1,22 @@ use std::error::Error; -use cdevents_sdk::{CDEvent, Context, Subject, pipelinerun_finished, Content}; +use cdevents_sdk::{CDEvent, Subject, pipelinerun_finished}; use cloudevents::{Event, AttributesReader}; -use time::OffsetDateTime; fn main() -> Result<(), Box> { - let cdevent = CDEvent { - context: Context { - version: "0.3.0".to_string(), - id: "271069a8-fc18-44f1-b38f-9d70a1695819".to_string(), - r#type: "dev.cdevents.pipelinerun .finished.0.1.1".to_string(), - source: "/event/source/123".try_into()?, - timestamp: OffsetDateTime::now_utc(), - }, - subject: Subject { - id: "/dev/pipeline/run/1".to_string(), - source: Some("https://dev.pipeline.run/source".try_into()?), - r#type: "build".to_string(), - content: Content::PipelinerunFinished(pipelinerun_finished::Content{ - errors: Some("pipelineErrors".into()), - outcome: Some("success".into()), - pipeline_name: Some("testPipeline".into()), - url: Some("https://dev.pipeline.run/source".into()) - }) - }, - custom_data: None, - custom_data_content_type: None, - }; + let cdevent = CDEvent::from( + Subject::from(pipelinerun_finished::Content{ + errors: Some("pipelineErrors".into()), + outcome: Some("success".into()), + pipeline_name: Some("testPipeline".into()), + url: Some("https://dev.pipeline.run/url".into()) + }) + .with_id("/dev/pipeline/run/1") + .with_source("https://dev.pipeline.run/source".try_into()?) + ) + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819") + .with_source("https://dev.cdevents".try_into()?) + ; let cdevent_expected = cdevent.clone(); @@ -44,7 +34,8 @@ fn main() -> Result<(), Box> { let cloudevent_received: Event = cloudevent.clone(); let cdevent_extracted: CDEvent = cloudevent_received.try_into()?; - assert_eq!(cloudevent.id(), cdevent_extracted.context.id); + assert_eq!(cloudevent.id(), cdevent_extracted.id()); assert_eq!(cdevent_expected, cdevent_extracted); Ok(()) } + diff --git a/cdevents-sdk/src/cdevent.rs b/cdevents-sdk/src/cdevent.rs index 6325762..258bff3 100644 --- a/cdevents-sdk/src/cdevent.rs +++ b/cdevents-sdk/src/cdevent.rs @@ -1,4 +1,4 @@ -use crate::{Context, Subject}; +use crate::{Context, Subject, UriReference}; use serde::{ de::{self, Deserializer, MapAccess, Visitor}, Deserialize, Serialize, @@ -8,15 +8,107 @@ use std::fmt; #[derive(Debug, Clone, Serialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct CDEvent { - pub context: Context, - pub subject: Subject, + context: Context, + subject: Subject, #[serde(rename = "customData", skip_serializing_if = "Option::is_none")] - pub custom_data: Option, + custom_data: Option, #[serde( rename = "customDataContentType", skip_serializing_if = "Option::is_none" )] - pub custom_data_content_type: Option, + custom_data_content_type: Option, +} + +impl From for CDEvent { + fn from(subject: Subject) -> Self { + let context = Context { + ty: subject.ty().into(), + ..Default::default() + }; + Self { + context, + subject, + custom_data: None, + custom_data_content_type: None, + } + } +} + +impl CDEvent { + /// see + pub fn version(&self) -> &str { + self.context.version.as_str() + } + + pub fn with_version(mut self, v: T) -> Self where T: Into { + self.context.version = v.into(); + self + } + + /// see + pub fn id(&self) -> &str { + self.context.id.as_str() + } + + pub fn with_id(mut self, v: T) -> Self where T: Into { + self.context.id = v.into(); + self + } + + /// see + pub fn source(&self) -> &UriReference { + &self.context.source + } + + pub fn with_source(mut self, v: UriReference) -> Self { + self.context.source = v; + self + } + + /// see + pub fn timestamp(&self) -> &time::OffsetDateTime { + &self.context.timestamp + } + + pub fn with_timestamp(mut self, v: time::OffsetDateTime) -> Self { + self.context.timestamp = v; + self + } + + /// see + pub fn subject(&self) -> &Subject { + &self.subject + } + + /// see + /// derived from subject.content + pub fn ty(&self) -> &str { + //self.context.ty() + self.subject.ty() + } + + /// see + pub fn custom_data(&self) -> &Option { + &self.custom_data + } + + pub fn with_custom_data(mut self, custom_data: serde_json::Value) -> Self { + self.custom_data = Some(custom_data); + self + } + + /// see + pub fn custom_data_content_type(&self) -> &Option { + &self.custom_data_content_type + } + + pub fn with_custom_data_content_type( + mut self, + custom_data_content_type: String, + ) -> Self { + self.custom_data_content_type = Some(custom_data_content_type); + self + } } impl<'de> Deserialize<'de> for CDEvent { @@ -82,7 +174,7 @@ impl<'de> Deserialize<'de> for CDEvent { let subject_json = subject_json.ok_or_else(|| de::Error::missing_field("subject"))?; let subject = - Subject::from_json(&context.r#type, subject_json).map_err(de::Error::custom)?; + Subject::from_json(&context.ty, subject_json).map_err(de::Error::custom)?; Ok(CDEvent { context, diff --git a/cdevents-sdk/src/cloudevents.rs b/cdevents-sdk/src/cloudevents.rs index 074084e..f7fc72d 100644 --- a/cdevents-sdk/src/cloudevents.rs +++ b/cdevents-sdk/src/cloudevents.rs @@ -13,11 +13,11 @@ impl BuilderExt for cloudevents::EventBuilderV10 { fn with_cdevent(self, cdevent: CDEvent) -> Result { Ok( - self.id(&cdevent.context.id) - .ty(&cdevent.context.r#type) - .source(cdevent.context.source.as_str()) - .subject(&cdevent.subject.id) - .time(cdevent.context.timestamp.format(&Rfc3339).map_err(|e| Self::Error::Other{source: Box::new(e)})?) + self.id(cdevent.id()) + .ty(cdevent.ty()) + .source(cdevent.source().as_str()) + .subject(cdevent.subject().id()) + .time(cdevent.timestamp().format(&Rfc3339).map_err(|e| Self::Error::Other{source: Box::new(e)})?) .data("application/json", serde_json::to_value(cdevent).map_err(Self::Error::from)?) ) } @@ -61,32 +61,19 @@ impl TryFrom for CDEvent { #[cfg(test)] mod tests { use ::cloudevents::{AttributesReader, EventBuilder, EventBuilderV10}; - use ::time::OffsetDateTime; - use crate::*; - use super::*; #[test] - fn test_true() -> Result<(), Box> { - let cdevent = CDEvent { - context: Context { - version: "0.3.0".to_string(), - id: "271069a8-fc18-44f1-b38f-9d70a1695819".to_string(), - r#type: "dev.cdevents.build.queued.0.1.1".to_string(), - source: "/event/source/123".try_into()?, - timestamp: OffsetDateTime::now_utc(), - }, - subject: Subject { - id: "subject123".to_string(), - source: Some("/event/source/123".try_into()?), - r#type: "build".to_string(), - content: Content::BuildQueued(build_queued::Content{}) - }, - custom_data: None, - custom_data_content_type: None, - }; - + fn test_into_cloudevent() -> Result<(), Box> { + let cdevent = CDEvent::from( + Subject::from(build_queued::Content{}) + .with_id("subject123") + .with_source("/event/source/123".try_into()?) + ) + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819") + .with_source("https://dev.cdevents".try_into()?) + ; let cloudevent_via_builder = EventBuilderV10::new() .with_cdevent(cdevent.clone())? @@ -95,11 +82,11 @@ mod tests { assert_eq!(cloudevent_via_builder, cloudevent); assert_eq!(cloudevent.id(), "271069a8-fc18-44f1-b38f-9d70a1695819"); - assert_eq!(cloudevent.id(), cdevent.context.id); + assert_eq!(cloudevent.id(), cdevent.id()); let (_, _, data) = cloudevent.take_data(); let cdevent_extracted: CDEvent = data.ok_or(Error::DataNotFoundInCloudEvent)?.try_into()?; - assert_eq!(cloudevent.id(), cdevent_extracted.context.id); + assert_eq!(cloudevent.id(), cdevent_extracted.id()); assert_eq!(cdevent, cdevent_extracted); Ok(()) } diff --git a/cdevents-sdk/src/context.rs b/cdevents-sdk/src/context.rs index 5d7658c..cd891f4 100644 --- a/cdevents-sdk/src/context.rs +++ b/cdevents-sdk/src/context.rs @@ -4,14 +4,14 @@ use crate::UriReference; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] -pub struct Context { - pub version: String, - pub id: String, - pub source: UriReference, +pub(crate) struct Context { + pub(crate) version: String, + pub(crate) id: String, + pub(crate) source: UriReference, #[serde(rename = "type")] - pub r#type: String, + pub(crate) ty: String, #[serde(with = "crate::serde::datetime")] - pub timestamp: time::OffsetDateTime, + pub(crate) timestamp: time::OffsetDateTime, } impl Default for Context { @@ -20,7 +20,7 @@ impl Default for Context { version: "0.3.0".into(), id: "00000000-0000-0000-0000-000000000000".into(), source: UriReference::default(), - r#type: "dev.cdevents.undef.undef.0.0.0".into(), + ty: "dev.cdevents.undef.undef.0.0.0".into(), timestamp: time::OffsetDateTime::now_utc(), } } diff --git a/cdevents-sdk/src/generated/mod.rs b/cdevents-sdk/src/generated/mod.rs index 3facfa3..0cd19d9 100644 --- a/cdevents-sdk/src/generated/mod.rs +++ b/cdevents-sdk/src/generated/mod.rs @@ -134,159 +134,159 @@ impl Content { match ty { ARTIFACT_PACKAGED => { let variant: artifact_packaged::Content = serde_json::from_value(json)?; - Ok(Self::ArtifactPackaged(variant)) + Ok(variant.into()) }, ARTIFACT_PUBLISHED => { let variant: artifact_published::Content = serde_json::from_value(json)?; - Ok(Self::ArtifactPublished(variant)) + Ok(variant.into()) }, ARTIFACT_SIGNED => { let variant: artifact_signed::Content = serde_json::from_value(json)?; - Ok(Self::ArtifactSigned(variant)) + Ok(variant.into()) }, BRANCH_CREATED => { let variant: branch_created::Content = serde_json::from_value(json)?; - Ok(Self::BranchCreated(variant)) + Ok(variant.into()) }, BRANCH_DELETED => { let variant: branch_deleted::Content = serde_json::from_value(json)?; - Ok(Self::BranchDeleted(variant)) + Ok(variant.into()) }, BUILD_FINISHED => { let variant: build_finished::Content = serde_json::from_value(json)?; - Ok(Self::BuildFinished(variant)) + Ok(variant.into()) }, BUILD_QUEUED => { let variant: build_queued::Content = serde_json::from_value(json)?; - Ok(Self::BuildQueued(variant)) + Ok(variant.into()) }, BUILD_STARTED => { let variant: build_started::Content = serde_json::from_value(json)?; - Ok(Self::BuildStarted(variant)) + Ok(variant.into()) }, CHANGE_ABANDONED => { let variant: change_abandoned::Content = serde_json::from_value(json)?; - Ok(Self::ChangeAbandoned(variant)) + Ok(variant.into()) }, CHANGE_CREATED => { let variant: change_created::Content = serde_json::from_value(json)?; - Ok(Self::ChangeCreated(variant)) + Ok(variant.into()) }, CHANGE_MERGED => { let variant: change_merged::Content = serde_json::from_value(json)?; - Ok(Self::ChangeMerged(variant)) + Ok(variant.into()) }, CHANGE_REVIEWED => { let variant: change_reviewed::Content = serde_json::from_value(json)?; - Ok(Self::ChangeReviewed(variant)) + Ok(variant.into()) }, CHANGE_UPDATED => { let variant: change_updated::Content = serde_json::from_value(json)?; - Ok(Self::ChangeUpdated(variant)) + Ok(variant.into()) }, ENVIRONMENT_CREATED => { let variant: environment_created::Content = serde_json::from_value(json)?; - Ok(Self::EnvironmentCreated(variant)) + Ok(variant.into()) }, ENVIRONMENT_DELETED => { let variant: environment_deleted::Content = serde_json::from_value(json)?; - Ok(Self::EnvironmentDeleted(variant)) + Ok(variant.into()) }, ENVIRONMENT_MODIFIED => { let variant: environment_modified::Content = serde_json::from_value(json)?; - Ok(Self::EnvironmentModified(variant)) + Ok(variant.into()) }, INCIDENT_DETECTED => { let variant: incident_detected::Content = serde_json::from_value(json)?; - Ok(Self::IncidentDetected(variant)) + Ok(variant.into()) }, INCIDENT_REPORTED => { let variant: incident_reported::Content = serde_json::from_value(json)?; - Ok(Self::IncidentReported(variant)) + Ok(variant.into()) }, INCIDENT_RESOLVED => { let variant: incident_resolved::Content = serde_json::from_value(json)?; - Ok(Self::IncidentResolved(variant)) + Ok(variant.into()) }, PIPELINERUN_FINISHED => { let variant: pipelinerun_finished::Content = serde_json::from_value(json)?; - Ok(Self::PipelinerunFinished(variant)) + Ok(variant.into()) }, PIPELINERUN_QUEUED => { let variant: pipelinerun_queued::Content = serde_json::from_value(json)?; - Ok(Self::PipelinerunQueued(variant)) + Ok(variant.into()) }, PIPELINERUN_STARTED => { let variant: pipelinerun_started::Content = serde_json::from_value(json)?; - Ok(Self::PipelinerunStarted(variant)) + Ok(variant.into()) }, REPOSITORY_CREATED => { let variant: repository_created::Content = serde_json::from_value(json)?; - Ok(Self::RepositoryCreated(variant)) + Ok(variant.into()) }, REPOSITORY_DELETED => { let variant: repository_deleted::Content = serde_json::from_value(json)?; - Ok(Self::RepositoryDeleted(variant)) + Ok(variant.into()) }, REPOSITORY_MODIFIED => { let variant: repository_modified::Content = serde_json::from_value(json)?; - Ok(Self::RepositoryModified(variant)) + Ok(variant.into()) }, SERVICE_DEPLOYED => { let variant: service_deployed::Content = serde_json::from_value(json)?; - Ok(Self::ServiceDeployed(variant)) + Ok(variant.into()) }, SERVICE_PUBLISHED => { let variant: service_published::Content = serde_json::from_value(json)?; - Ok(Self::ServicePublished(variant)) + Ok(variant.into()) }, SERVICE_REMOVED => { let variant: service_removed::Content = serde_json::from_value(json)?; - Ok(Self::ServiceRemoved(variant)) + Ok(variant.into()) }, SERVICE_ROLLEDBACK => { let variant: service_rolledback::Content = serde_json::from_value(json)?; - Ok(Self::ServiceRolledback(variant)) + Ok(variant.into()) }, SERVICE_UPGRADED => { let variant: service_upgraded::Content = serde_json::from_value(json)?; - Ok(Self::ServiceUpgraded(variant)) + Ok(variant.into()) }, TASKRUN_FINISHED => { let variant: taskrun_finished::Content = serde_json::from_value(json)?; - Ok(Self::TaskrunFinished(variant)) + Ok(variant.into()) }, TASKRUN_STARTED => { let variant: taskrun_started::Content = serde_json::from_value(json)?; - Ok(Self::TaskrunStarted(variant)) + Ok(variant.into()) }, TESTCASERUN_FINISHED => { let variant: testcaserun_finished::Content = serde_json::from_value(json)?; - Ok(Self::TestcaserunFinished(variant)) + Ok(variant.into()) }, TESTCASERUN_QUEUED => { let variant: testcaserun_queued::Content = serde_json::from_value(json)?; - Ok(Self::TestcaserunQueued(variant)) + Ok(variant.into()) }, TESTCASERUN_STARTED => { let variant: testcaserun_started::Content = serde_json::from_value(json)?; - Ok(Self::TestcaserunStarted(variant)) + Ok(variant.into()) }, TESTOUTPUT_PUBLISHED => { let variant: testoutput_published::Content = serde_json::from_value(json)?; - Ok(Self::TestoutputPublished(variant)) + Ok(variant.into()) }, TESTSUITERUN_FINISHED => { let variant: testsuiterun_finished::Content = serde_json::from_value(json)?; - Ok(Self::TestsuiterunFinished(variant)) + Ok(variant.into()) }, TESTSUITERUN_QUEUED => { let variant: testsuiterun_queued::Content = serde_json::from_value(json)?; - Ok(Self::TestsuiterunQueued(variant)) + Ok(variant.into()) }, TESTSUITERUN_STARTED => { let variant: testsuiterun_started::Content = serde_json::from_value(json)?; - Ok(Self::TestsuiterunStarted(variant)) + Ok(variant.into()) }, variant => Err(serde_json::Error::custom(format_args!( "unknown variant `{}`, expected 'dev.cdevents.{{subject}}.{{predicate}}.{{version}}'", @@ -294,4 +294,253 @@ impl Content { ))), } } + + pub fn ty(&self) -> &'static str { + match self { + Self::ArtifactPackaged(_) => ARTIFACT_PACKAGED, + Self::ArtifactPublished(_) => ARTIFACT_PUBLISHED, + Self::ArtifactSigned(_) => ARTIFACT_SIGNED, + Self::BranchCreated(_) => BRANCH_CREATED, + Self::BranchDeleted(_) => BRANCH_DELETED, + Self::BuildFinished(_) => BUILD_FINISHED, + Self::BuildQueued(_) => BUILD_QUEUED, + Self::BuildStarted(_) => BUILD_STARTED, + Self::ChangeAbandoned(_) => CHANGE_ABANDONED, + Self::ChangeCreated(_) => CHANGE_CREATED, + Self::ChangeMerged(_) => CHANGE_MERGED, + Self::ChangeReviewed(_) => CHANGE_REVIEWED, + Self::ChangeUpdated(_) => CHANGE_UPDATED, + Self::EnvironmentCreated(_) => ENVIRONMENT_CREATED, + Self::EnvironmentDeleted(_) => ENVIRONMENT_DELETED, + Self::EnvironmentModified(_) => ENVIRONMENT_MODIFIED, + Self::IncidentDetected(_) => INCIDENT_DETECTED, + Self::IncidentReported(_) => INCIDENT_REPORTED, + Self::IncidentResolved(_) => INCIDENT_RESOLVED, + Self::PipelinerunFinished(_) => PIPELINERUN_FINISHED, + Self::PipelinerunQueued(_) => PIPELINERUN_QUEUED, + Self::PipelinerunStarted(_) => PIPELINERUN_STARTED, + Self::RepositoryCreated(_) => REPOSITORY_CREATED, + Self::RepositoryDeleted(_) => REPOSITORY_DELETED, + Self::RepositoryModified(_) => REPOSITORY_MODIFIED, + Self::ServiceDeployed(_) => SERVICE_DEPLOYED, + Self::ServicePublished(_) => SERVICE_PUBLISHED, + Self::ServiceRemoved(_) => SERVICE_REMOVED, + Self::ServiceRolledback(_) => SERVICE_ROLLEDBACK, + Self::ServiceUpgraded(_) => SERVICE_UPGRADED, + Self::TaskrunFinished(_) => TASKRUN_FINISHED, + Self::TaskrunStarted(_) => TASKRUN_STARTED, + Self::TestcaserunFinished(_) => TESTCASERUN_FINISHED, + Self::TestcaserunQueued(_) => TESTCASERUN_QUEUED, + Self::TestcaserunStarted(_) => TESTCASERUN_STARTED, + Self::TestoutputPublished(_) => TESTOUTPUT_PUBLISHED, + Self::TestsuiterunFinished(_) => TESTSUITERUN_FINISHED, + Self::TestsuiterunQueued(_) => TESTSUITERUN_QUEUED, + Self::TestsuiterunStarted(_) => TESTSUITERUN_STARTED, + } + } + + pub fn subject_predicate(&self) -> (&'static str, &'static str){ + let mut split = self.ty().split('.'); + ( + split.nth(2).expect("fargment 2 of ty should always exists"), + split.nth(3).expect("fargment 3 of ty should always exists") + ) + } + +} + +impl From for Content { + fn from(value: artifact_packaged::Content) -> Self { + Self::ArtifactPackaged(value) + } +} +impl From for Content { + fn from(value: artifact_published::Content) -> Self { + Self::ArtifactPublished(value) + } +} +impl From for Content { + fn from(value: artifact_signed::Content) -> Self { + Self::ArtifactSigned(value) + } +} +impl From for Content { + fn from(value: branch_created::Content) -> Self { + Self::BranchCreated(value) + } +} +impl From for Content { + fn from(value: branch_deleted::Content) -> Self { + Self::BranchDeleted(value) + } +} +impl From for Content { + fn from(value: build_finished::Content) -> Self { + Self::BuildFinished(value) + } +} +impl From for Content { + fn from(value: build_queued::Content) -> Self { + Self::BuildQueued(value) + } +} +impl From for Content { + fn from(value: build_started::Content) -> Self { + Self::BuildStarted(value) + } +} +impl From for Content { + fn from(value: change_abandoned::Content) -> Self { + Self::ChangeAbandoned(value) + } +} +impl From for Content { + fn from(value: change_created::Content) -> Self { + Self::ChangeCreated(value) + } +} +impl From for Content { + fn from(value: change_merged::Content) -> Self { + Self::ChangeMerged(value) + } +} +impl From for Content { + fn from(value: change_reviewed::Content) -> Self { + Self::ChangeReviewed(value) + } +} +impl From for Content { + fn from(value: change_updated::Content) -> Self { + Self::ChangeUpdated(value) + } +} +impl From for Content { + fn from(value: environment_created::Content) -> Self { + Self::EnvironmentCreated(value) + } +} +impl From for Content { + fn from(value: environment_deleted::Content) -> Self { + Self::EnvironmentDeleted(value) + } +} +impl From for Content { + fn from(value: environment_modified::Content) -> Self { + Self::EnvironmentModified(value) + } +} +impl From for Content { + fn from(value: incident_detected::Content) -> Self { + Self::IncidentDetected(value) + } +} +impl From for Content { + fn from(value: incident_reported::Content) -> Self { + Self::IncidentReported(value) + } +} +impl From for Content { + fn from(value: incident_resolved::Content) -> Self { + Self::IncidentResolved(value) + } +} +impl From for Content { + fn from(value: pipelinerun_finished::Content) -> Self { + Self::PipelinerunFinished(value) + } +} +impl From for Content { + fn from(value: pipelinerun_queued::Content) -> Self { + Self::PipelinerunQueued(value) + } +} +impl From for Content { + fn from(value: pipelinerun_started::Content) -> Self { + Self::PipelinerunStarted(value) + } +} +impl From for Content { + fn from(value: repository_created::Content) -> Self { + Self::RepositoryCreated(value) + } +} +impl From for Content { + fn from(value: repository_deleted::Content) -> Self { + Self::RepositoryDeleted(value) + } +} +impl From for Content { + fn from(value: repository_modified::Content) -> Self { + Self::RepositoryModified(value) + } +} +impl From for Content { + fn from(value: service_deployed::Content) -> Self { + Self::ServiceDeployed(value) + } +} +impl From for Content { + fn from(value: service_published::Content) -> Self { + Self::ServicePublished(value) + } +} +impl From for Content { + fn from(value: service_removed::Content) -> Self { + Self::ServiceRemoved(value) + } +} +impl From for Content { + fn from(value: service_rolledback::Content) -> Self { + Self::ServiceRolledback(value) + } +} +impl From for Content { + fn from(value: service_upgraded::Content) -> Self { + Self::ServiceUpgraded(value) + } +} +impl From for Content { + fn from(value: taskrun_finished::Content) -> Self { + Self::TaskrunFinished(value) + } +} +impl From for Content { + fn from(value: taskrun_started::Content) -> Self { + Self::TaskrunStarted(value) + } +} +impl From for Content { + fn from(value: testcaserun_finished::Content) -> Self { + Self::TestcaserunFinished(value) + } +} +impl From for Content { + fn from(value: testcaserun_queued::Content) -> Self { + Self::TestcaserunQueued(value) + } +} +impl From for Content { + fn from(value: testcaserun_started::Content) -> Self { + Self::TestcaserunStarted(value) + } +} +impl From for Content { + fn from(value: testoutput_published::Content) -> Self { + Self::TestoutputPublished(value) + } +} +impl From for Content { + fn from(value: testsuiterun_finished::Content) -> Self { + Self::TestsuiterunFinished(value) + } +} +impl From for Content { + fn from(value: testsuiterun_queued::Content) -> Self { + Self::TestsuiterunQueued(value) + } +} +impl From for Content { + fn from(value: testsuiterun_started::Content) -> Self { + Self::TestsuiterunStarted(value) + } } diff --git a/cdevents-sdk/src/generated/testcaserun_finished.rs b/cdevents-sdk/src/generated/testcaserun_finished.rs index 68bfcc2..018e348 100644 --- a/cdevents-sdk/src/generated/testcaserun_finished.rs +++ b/cdevents-sdk/src/generated/testcaserun_finished.rs @@ -37,7 +37,7 @@ pub struct TestCase { #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] - pub r#type: Option, + pub ty: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] pub uri: Option, #[serde(rename = "version", default, skip_serializing_if = "Option::is_none",)] diff --git a/cdevents-sdk/src/generated/testcaserun_queued.rs b/cdevents-sdk/src/generated/testcaserun_queued.rs index eab0fd4..72c1cf2 100644 --- a/cdevents-sdk/src/generated/testcaserun_queued.rs +++ b/cdevents-sdk/src/generated/testcaserun_queued.rs @@ -20,7 +20,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct Trigger { #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] - pub r#type: Option, + pub ty: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] pub uri: Option, } @@ -42,7 +42,7 @@ pub struct TestCase { #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] - pub r#type: Option, + pub ty: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] pub uri: Option, #[serde(rename = "version", default, skip_serializing_if = "Option::is_none",)] diff --git a/cdevents-sdk/src/generated/testcaserun_started.rs b/cdevents-sdk/src/generated/testcaserun_started.rs index eab0fd4..72c1cf2 100644 --- a/cdevents-sdk/src/generated/testcaserun_started.rs +++ b/cdevents-sdk/src/generated/testcaserun_started.rs @@ -20,7 +20,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct Trigger { #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] - pub r#type: Option, + pub ty: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] pub uri: Option, } @@ -42,7 +42,7 @@ pub struct TestCase { #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] pub name: Option, #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] - pub r#type: Option, + pub ty: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] pub uri: Option, #[serde(rename = "version", default, skip_serializing_if = "Option::is_none",)] diff --git a/cdevents-sdk/src/generated/testsuiterun_queued.rs b/cdevents-sdk/src/generated/testsuiterun_queued.rs index 15bb6bc..db1a1f7 100644 --- a/cdevents-sdk/src/generated/testsuiterun_queued.rs +++ b/cdevents-sdk/src/generated/testsuiterun_queued.rs @@ -18,7 +18,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct Trigger { #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] - pub r#type: Option, + pub ty: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] pub uri: Option, } diff --git a/cdevents-sdk/src/generated/testsuiterun_started.rs b/cdevents-sdk/src/generated/testsuiterun_started.rs index dea3cb7..f2c3ff4 100644 --- a/cdevents-sdk/src/generated/testsuiterun_started.rs +++ b/cdevents-sdk/src/generated/testsuiterun_started.rs @@ -18,7 +18,7 @@ pub struct Content { #[serde(deny_unknown_fields)] pub struct Trigger { #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] - pub r#type: Option, + pub ty: Option, #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] pub uri: Option, } diff --git a/cdevents-sdk/src/lib.rs b/cdevents-sdk/src/lib.rs index dada526..819f4f8 100644 --- a/cdevents-sdk/src/lib.rs +++ b/cdevents-sdk/src/lib.rs @@ -14,7 +14,7 @@ mod uri; mod uri_reference; pub use cdevent::*; -pub use context::*; +pub(crate) use context::*; pub use error::*; pub use generated::*; pub use subject::*; diff --git a/cdevents-sdk/src/subject.rs b/cdevents-sdk/src/subject.rs index e91bc25..887b156 100644 --- a/cdevents-sdk/src/subject.rs +++ b/cdevents-sdk/src/subject.rs @@ -4,31 +4,64 @@ use serde::{Deserialize, Serialize}; use crate::{Content, UriReference}; +/// see #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct Subject { #[serde(rename = "content")] - pub content: Content, + content: Content, #[serde(rename = "id")] - pub id: String, + id: String, #[serde( rename = "source", default, skip_serializing_if = "Option::is_none", )] - pub source: Option, + source: Option, #[serde(rename = "type")] - pub r#type: String, + ty: String, } impl Subject { + /// see + pub fn id(&self) -> &str { + &self.id + } + + pub fn with_id(mut self, id: T) -> Self + where T: Into { + self.id = id.into(); + self + } + + /// see + pub fn source(&self) -> &Option { + &self.source + } + + pub fn with_source(mut self, source: UriReference) -> Self { + self.source = Some(source); + self + } + + /// see + /// derived from content + pub fn ty(&self) -> &str { + &self.ty + } + + /// see + pub fn content(&self) -> &Content { + &self.content + } + pub fn from_json(ty: &str, json: serde_json::Value) -> Result { Ok(Subject { id: json["id"] .as_str() .ok_or_else(|| serde::de::Error::missing_field("id"))? .to_string(), - r#type: json["type"] + ty: json["type"] .as_str() .ok_or_else(|| serde::de::Error::missing_field("type"))? .to_string(), @@ -42,3 +75,16 @@ impl Subject { }) } } + +impl From for Subject where T: Into{ + fn from(content: T) -> Self { + let content = content.into(); + let ty = content.ty().to_owned(); + Self { + content, + id: String::new(), + source: None, + ty, + } + } +} diff --git a/generator/src/main.rs b/generator/src/main.rs index 22f5e10..40ffdc1 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -189,7 +189,7 @@ fn collect_structs( .map(|field| { let serde_name = field.0.to_string(); let rust_name = if serde_name == "type" { - "r#type".to_string() + "ty".to_string() } else { serde_name.to_snake_case() }; diff --git a/generator/templates/mod.hbs b/generator/templates/mod.hbs index 1384284..5d3ef83 100644 --- a/generator/templates/mod.hbs +++ b/generator/templates/mod.hbs @@ -27,7 +27,7 @@ impl Content { {{#each variants }} {{to_screaming_snake_case this.rust_module}} => { let variant: {{this.rust_module}}::Content = serde_json::from_value(json)?; - Ok(Self::{{to_class_case this.rust_module}}(variant)) + Ok(variant.into()) }, {{/each}} variant => Err(serde_json::Error::custom(format_args!( @@ -36,4 +36,29 @@ impl Content { ))), } } + + pub fn ty(&self) -> &'static str { + match self { + {{#each variants }} + Self::{{to_class_case this.rust_module}}(_) => {{to_screaming_snake_case this.rust_module}}, + {{/each}} + } + } + + pub fn subject_predicate(&self) -> (&'static str, &'static str){ + let mut split = self.ty().split('.'); + ( + split.nth(2).expect("fargment 2 of ty should always exists"), + split.nth(3).expect("fargment 3 of ty should always exists") + ) + } + +} + +{{#each variants }} +impl From<{{this.rust_module}}::Content> for Content { + fn from(value: {{this.rust_module}}::Content) -> Self { + Self::{{to_class_case this.rust_module}}(value) + } } +{{/each}}