diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e221a3c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,56 @@ +# https://editorconfig.org/ + +root = true + +[*] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true +end_of_line = lf +charset = utf-8 + +[*.conf] +indent_size = 2 + +[*.md] +#inside code block, indentation could be anything +indent_size = unset + +[*.rs] +# https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/guide.md +indent_size = 4 +# officially the limit is 100, but we have long url (unsplittable) in comment +max_line_length = 200 + +[{*.bazel,*.bzl,BUILD,WORKSPACE}] +indent_size = 4 + +# The JSON files contain newlines inconsistently +[*.json] +insert_final_newline = unset + +[**/vendor/**] +indent_style = unset +indent_size = unset +insert_final_newline = unset + +# Minified JavaScript files shouldn't be changed +[**.min.js] +indent_style = unset +indent_size = unset +insert_final_newline = unset + +# Makefiles always use tabs for indentation +[Makefile] +indent_style = tab +indent_size = 4 + +[justfile] +indent_style = space +indent_size = 4 + +# Batch files use tabs for indentation +[*.bat] +indent_style = tab +indent_size = 4 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..62a183b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + # Workflow files stored in the + # default location of `.github/workflows` + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index 6dbd883..61a153b 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -47,6 +47,9 @@ jobs: steps: - name: Run the checkout command uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: "true" - name: Install rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 with: @@ -66,8 +69,8 @@ jobs: ~/.cargo/git/db/ key: ${{ runner.os }}-sdk-rust-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-sdk-rust- + ${{ runner.os }}-sdk-rust- - name: Check cargo version run: cargo --version - - name: Run lint ${{ matrix.lint_projects }} + - name: Run ${{ matrix.lint_projects }} run: make -f Makefile lint_${{ matrix.lint_projects }} diff --git a/.gitignore b/.gitignore index 6985cf1..35a3f8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,161 @@ +# Created by https://www.toptal.com/developers/gitignore/api/git,vim,rust,emacs,jetbrains+all,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=git,vim,rust,emacs,jetbrains+all,visualstudiocode + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Rust ### # Generated by Cargo # will have compiled files and executables debug/ @@ -12,3 +170,46 @@ Cargo.lock # MSVC Windows builds of rustc generate these, which store debugging information *.pdb + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/git,vim,rust,emacs,jetbrains+all,visualstudiocode + +megalinter-reports diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..72bdf71 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "cdevents-spec"] + path = cdevents-spec + url = https://github.com/cdevents/spec.git + branch = spec-v0.3 diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 0000000..5cb09ed --- /dev/null +++ b/.mise.toml @@ -0,0 +1,16 @@ +[env] +# RUSTC_WRAPPER = "sccache" +RUST_WITHOUT = "rust-docs" +# ASDF_RUST_PROFILE = "minimal" +MISE_CARGO_BINSTALL = "true" + +[tools] +rust = "1.75" +make = "latest" +# # experimental +"cargo:cargo-binstall" = "latest" +"cargo:cargo-nextest" = "0.9" +# "cargo:cargo-hack" = "latest" +"cargo:cargo-deny" = "0.14" +# "cargo:git-cliff" = "latest" +"cargo:dprint" = "0.45" diff --git a/Cargo.toml b/Cargo.toml index b482c38..165a472 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,21 @@ -[workspace] -members = [ - "bindings", - "factory", - "types", - "zz_artifact", - "zz_branch", - "zz_build", - "zz_change", - "zz_environment", - "zz_incident", - "zz_pipeline", - "zz_repository", - "zz_service", - "zz_task", -] +[workspace] +resolver = "2" +members = ["cdevents-sdk", "generator"] + +[workspace.package] +edition = "2021" +version = "0.1.0" +authors = [ + # The actual list of contributors can be retrieved from the git log + "The CDEvents Rust SDK Authors", +] +license = "Apache-2.0" +repository = "https://github.com/cdevents/sdk-rust" +rust-version = "1.75" +publish = false + +[workspace.metadata.release] +pre-release-commit-message = "๐Ÿš€ (cargo-release) version {{version}}" +tag-prefix = "" +tag-name = "{{prefix}}{{version}}" +tag-message = "๐Ÿ”– {{version}}" diff --git a/Makefile b/Makefile index bdac2d6..ca42967 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,51 @@ +build_docs: + cargo doc --no-deps +build_examples: + cargo build --examples +build: + cargo build +build_release: + cargo build --release +build_release_%: + cargo build --release --package $* +build_%: + cargo build --package $* + +check: + cargo hack check --each-feature + +check_no_std: + cargo --version + cargo check --target thumbv7em-none-eabihf -p ockam --no-default-features --features 'no_std alloc software_vault' + # no_std example project + cd examples/rust/example_projects/no_std + cargo check --example hello + +check_cargo_update: + cargo --version + # TODO: uncomment when tauri version is updated + # rm -rf Cargo.lock + # cargo update + # cargo check + +# no uncommitted changes on sdk (generated code) +check_no_uncommitted_changes_on_sdk: + git diff --exit-code cdevents-sdk + lint: lint_cargo_fmt_check lint_cargo_deny lint_cargo_clippy lint_cargo_fmt_check: cargo fmt --all -- --check lint_cargo_deny: - cargo deny --all-features \ + cargo deny --workspace --all-features \ + --exclude-dev \ + --exclude generator \ check licenses advisories \ --config=tools/cargo-deny/deny.toml lint_cargo_clippy: - cargo clippy --no-deps --all-targets -- -D warnings + cargo clippy --workspace --all-features --no-deps --all-targets -- --deny warnings lint_cargo_toml_fmt_files: dprint fmt --config=tools/dprint/dprint.json @@ -20,7 +56,16 @@ lint_cargo_toml_check_files: clean: cargo clean +generate: + cargo run -p generator -- --templates-dir "generator/templates" --jsonschema-dir "cdevents-spec/schemas" --dest "cdevents-sdk/src/generated" + +test: + cargo nextest run --all-features + cargo test --doc + .PHONY: - check \ + generate \ + check check_no_uncommitted_changes_on_sdk \ + test \ lint lint_cargo_fmt_check lint_cargo_deny lint_cargo_clippy lint_cargo_toml_files lint_cargo_readme lint_cargo_readme_% lint_cargo_toml_files \ clean clean_% very_clean format diff --git a/README.md b/README.md index 2090aab..fe53265 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,67 @@ -# Rust CDEvents SDK - -Rust SDK to emit [CDEvents](https://cdevents.dev). - -The SDK can be used to create CDEvents and send them as CloudEvents, as well as parse a received CloudEvent into a CDEvent. - -## Get started - -```rust -WIP -``` - -## Create your first CDEvent - -To create a CDEvent, for instance a [*pipelineRun queued*](https://cdevents.dev/docs/core/#pipelinerun-queued) one: - -```rust -WIP -``` - -## Send your first CDEvent as CloudEvent - -Import the modules in your code - -```rust -WIP -``` - -To send a CDEvent as CloudEvent: - -```rust -WIP -``` - -See the [CloudEvents](https://github.com/cloudevents/sdk-go#send-your-first-cloudevent) docs as well. - -## Contributing - -If you would like to contribute, see our [development](DEVELOPMENT.md) guide. - -## References - -- [CDEvents](https://cdevents.dev) \ No newline at end of file +# Rust CDEvents SDK + +Rust SDK to emit [CDEvents](https://cdevents.dev). + +The SDK can be used to create CDEvents and send them as CloudEvents, as well as parse a received CloudEvent into a CDEvent. + +## Create and send your first CDEvent as CloudEvent + +Import the modules in your code + +```toml +cdevents = "0.1.0" +``` + +To send a CDEvent as CloudEvent: + +```rust +// from examples/pipelinerun_finished.rs +use std::error::Error; + +use cdevents_sdk::{CDEvent, Subject, pipelinerun_finished, Content}; +use cloudevents::{Event, AttributesReader}; + +fn main() -> Result<(), Box> { + 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".try_into()?) + .with_source("https://dev.pipeline.run/source".try_into()?) + ) + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819".try_into()?) + .with_source("https://dev.cdevents".try_into()?) + ; + + let cdevent_expected = cdevent.clone(); + + // shortcut for creating cloudevents with + // + // ```rust + // use cloudevents::event::EventBuilderV10; + // use cdevents_sdk::cloudevents::BuilderExt; + // + // let mut cloudevent = EventBuilderV10::new().with_cdevent(cdevent.clone())?.build()?; + // ``` + let cloudevent: Event = cdevent.try_into()?; + + // zero transport, but cloning + let cloudevent_received: Event = cloudevent.clone(); + let cdevent_extracted: CDEvent = cloudevent_received.try_into()?; + + assert_eq!(cloudevent.id(), cdevent_extracted.id().to_string()); + assert_eq!(cdevent_expected, cdevent_extracted); + Ok(()) +} +``` + +See the [CloudEvents](https://github.com/cloudevents/sdk-rust) docs as well. + +## References + +- [CDEvents](https://cdevents.dev) +- [CDEvents Primer](https://cdevents.dev/docs/primer/) +- [CDEvents Specification](https://cdevents.dev/docs/) diff --git a/bindings/Cargo.toml b/bindings/Cargo.toml deleted file mode 100644 index 65745a0..0000000 --- a/bindings/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "bindings" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/bindings/src/main.rs b/bindings/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/bindings/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/cdevents-sdk/.rustfmt.toml b/cdevents-sdk/.rustfmt.toml new file mode 100644 index 0000000..9dc8a31 --- /dev/null +++ b/cdevents-sdk/.rustfmt.toml @@ -0,0 +1,9 @@ +# see https://rust-lang.github.io/rustfmt/ + +# - disable all formatting until support of `ignore` or `generated` +# - the marker `#![rustfmt::skip]` generates an `error: custom inner attributes are unstable` on clippy,... +disable_all_formatting = true + +# unstable_features = true # nightly only +# ignore = ["generated"] # unstable +# format_generated_files = false # unstable diff --git a/cdevents-sdk/Cargo.toml b/cdevents-sdk/Cargo.toml new file mode 100644 index 0000000..f38f150 --- /dev/null +++ b/cdevents-sdk/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "cdevents-sdk" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +publish = true +repository.workspace = true +rust-version.workspace = true +description = "A Rust SDK for CDEvents" + +[dependencies] +cloudevents-sdk = { version = "0.7", optional = true, default-features = false } +fluent-uri = "0.1" +proptest = { version = "1.4", optional = true } +proptest-derive = { version = "0.4", optional = true } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +time = { version = "0.3", features = ["serde-human-readable"] } + +[dev-dependencies] +assert-json-diff = "2.0" +boon = "0.5" +proptest = "1" +rstest = "0.18" + +[features] +default = ["cloudevents"] +# provide cloudevents helpers and extensions +cloudevents = ["dep:cloudevents-sdk"] +# provide test helpers (proptest'strategies and arbitraries for struct generation) +testkit = ["dep:proptest", "dep:proptest-derive"] diff --git a/cdevents-sdk/examples/pipelinerun_finished.rs b/cdevents-sdk/examples/pipelinerun_finished.rs new file mode 100644 index 0000000..12a5c07 --- /dev/null +++ b/cdevents-sdk/examples/pipelinerun_finished.rs @@ -0,0 +1,41 @@ +use std::error::Error; + +use cdevents_sdk::{CDEvent, Subject, pipelinerun_finished}; +use cloudevents::{Event, AttributesReader}; + +fn main() -> Result<(), Box> { + 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".try_into()?) + .with_source("https://dev.pipeline.run/source".try_into()?) + ) + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819".try_into()?) + .with_source("https://dev.cdevents".try_into()?) + ; + + let cdevent_expected = cdevent.clone(); + + // shortcut for creating cloudevents with + // + // ```rust + // use cloudevents::event::EventBuilderV10; + // use cdevents_sdk::cloudevents::BuilderExt; + // + // let mut cloudevent = EventBuilderV10::new().with_cdevent(cdevent.clone())?.build()?; + // ``` + let cloudevent: Event = cdevent.try_into()?; + + // zero transport, but cloning + let cloudevent_received: Event = cloudevent.clone(); + let cdevent_extracted: CDEvent = cloudevent_received.try_into()?; + + assert_eq!(cloudevent.id(), cdevent_extracted.id().to_string()); + assert_eq!(cdevent_expected, cdevent_extracted); + Ok(()) +} + diff --git a/cdevents-sdk/src/cdevent.rs b/cdevents-sdk/src/cdevent.rs new file mode 100644 index 0000000..ad4b53c --- /dev/null +++ b/cdevents-sdk/src/cdevent.rs @@ -0,0 +1,224 @@ +use crate::{Context, Id, Subject, UriReference}; +use serde::{ + de::{self, Deserializer, MapAccess, Visitor}, + Deserialize, Serialize, +}; +use std::fmt; + +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct CDEvent { + context: Context, + subject: Subject, + #[serde(rename = "customData", skip_serializing_if = "Option::is_none")] + custom_data: Option, + #[serde( + rename = "customDataContentType", + skip_serializing_if = "Option::is_none" + )] + custom_data_content_type: Option, +} + +impl From for CDEvent { + fn from(subject: Subject) -> Self { + let context = Context { + ty: subject.content().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) -> &Id { + &self.context.id + } + + pub fn with_id(mut self, v: Id) -> Self { + self.context.id = v; + 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.subject.content().ty() + self.context.ty.as_str() + } + + /// 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 { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(field_identifier, rename_all = "camelCase")] + enum Field { + Context, + Subject, + CustomData, + CustomDataContentType, + } + + struct CDEventVisitor; + + impl<'de> Visitor<'de> for CDEventVisitor { + type Value = CDEvent; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct CDEvent") + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut context: Option = None; + let mut subject_json: Option = None; + let mut custom_data = None; + let mut custom_data_content_type = None; + while let Some(key) = map.next_key()? { + match key { + Field::Context => { + if context.is_some() { + return Err(de::Error::duplicate_field("context")); + } + context = Some(map.next_value()?); + } + Field::Subject => { + if subject_json.is_some() { + return Err(de::Error::duplicate_field("subject")); + } + subject_json = Some(map.next_value()?); + } + Field::CustomData => { + if custom_data.is_some() { + return Err(de::Error::duplicate_field("customData")); + } + custom_data = Some(map.next_value()?); + } + Field::CustomDataContentType => { + if custom_data_content_type.is_some() { + return Err(de::Error::duplicate_field("customDataContentType")); + } + custom_data_content_type = Some(map.next_value()?); + } + } + } + let context = context.ok_or_else(|| de::Error::missing_field("context"))?; + let subject_json = + subject_json.ok_or_else(|| de::Error::missing_field("subject"))?; + let subject = + Subject::from_json(&context.ty, subject_json).map_err(de::Error::custom)?; + + Ok(CDEvent { + context, + subject, + custom_data, + custom_data_content_type, + }) + } + } + + const FIELDS: &[&str] = &["context", "subject"]; + deserializer.deserialize_struct("CDEvent", FIELDS, CDEventVisitor) + } +} + +#[cfg(feature = "testkit")] +impl<> proptest::arbitrary::Arbitrary for CDEvent { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::prelude::*; + ( + any::(), + any::(), + any::(), + ).prop_map(|(subject, id, source)| { + CDEvent::from(subject).with_id(id).with_source(source) + }).boxed() + } +} + +#[cfg(test)] +mod tests { + use crate::CDEvent; + use proptest::prelude::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} \ No newline at end of file diff --git a/cdevents-sdk/src/cloudevents.rs b/cdevents-sdk/src/cloudevents.rs new file mode 100644 index 0000000..0c674be --- /dev/null +++ b/cdevents-sdk/src/cloudevents.rs @@ -0,0 +1,93 @@ +use cloudevents::{Data, Event}; +use time::format_description::well_known::Rfc3339; + +use crate::CDEvent; + +pub trait BuilderExt: Sized { + type Error; + fn with_cdevent(self, cdevent: CDEvent) -> Result; +} + +impl BuilderExt for cloudevents::EventBuilderV10 { + type Error = cloudevents::message::Error; + + fn with_cdevent(self, cdevent: CDEvent) -> Result { + Ok( + 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)?) + ) + } +} + +impl TryFrom for Event { + type Error = cloudevents::message::Error; + + fn try_from(value: CDEvent) -> Result { + use ::cloudevents::{EventBuilder, EventBuilderV10}; + EventBuilderV10::new() + .with_cdevent(value)? + .build().map_err(Self::Error::from) + } +} + +impl TryFrom for CDEvent { + type Error = serde_json::Error; + + fn try_from(value: Data) -> Result { + let json = match value { + Data::Binary(v) => serde_json::from_slice(&v)?, + Data::Json(v) => v, + Data::String(s) => serde_json::from_str(&s)?, + }; + serde_json::from_value(json) //doesn't work due to the unsupported variant definition + } +} + +impl TryFrom for CDEvent { + type Error = crate::Error; + + fn try_from(value: Event) -> Result { + let mut event = value; + let (_, _, data) = event.take_data(); + data.ok_or(Self::Error::DataNotFoundInCloudEvent)? + .try_into().map_err(Self::Error::from) + } +} + +#[cfg(test)] +mod tests { + use ::cloudevents::{AttributesReader, EventBuilder, EventBuilderV10}; + use crate::*; + use super::*; + + #[test] + fn test_into_cloudevent() -> Result<(), Box> { + let cdevent = CDEvent::from( + Subject::from(build_queued::Content{}) + .with_id("subject123".try_into()?) + .with_source("/event/source/123".try_into()?) + ) + .with_id("271069a8-fc18-44f1-b38f-9d70a1695819".try_into()?) + .with_source("https://dev.cdevents".try_into()?) + ; + + let cloudevent_via_builder = EventBuilderV10::new() + .with_cdevent(cdevent.clone())? + .build()?; + let mut cloudevent: Event = cdevent.clone().try_into()?; + assert_eq!(cloudevent_via_builder, cloudevent); + + assert_eq!(cloudevent.id(), "271069a8-fc18-44f1-b38f-9d70a1695819"); + assert_eq!(cloudevent.id(), cdevent.id().to_string()); + + let (_, _, data) = cloudevent.take_data(); + let cdevent_extracted: CDEvent = data.ok_or(Error::DataNotFoundInCloudEvent)?.try_into()?; + assert_eq!(cloudevent.id(), cdevent_extracted.id().to_string()); + assert_eq!(cdevent, cdevent_extracted); + Ok(()) + } +} diff --git a/cdevents-sdk/src/context.rs b/cdevents-sdk/src/context.rs new file mode 100644 index 0000000..7845c5b --- /dev/null +++ b/cdevents-sdk/src/context.rs @@ -0,0 +1,27 @@ +use serde::{Deserialize, Serialize}; + +use crate::{Id, UriReference}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub(crate) struct Context { + pub(crate) version: String, + pub(crate) id: Id, + pub(crate) source: UriReference, + #[serde(rename = "type")] + pub(crate) ty: String, + #[serde(with = "crate::serde::datetime")] + pub(crate) timestamp: time::OffsetDateTime, +} + +impl Default for Context { + fn default() -> Self { + Self { + version: "0.3.0".into(), + id: Id::default(), + source: "/undef".try_into().expect("/undef is a valid uri-reference"), + ty: "dev.cdevents.undef.undef.0.0.0".into(), + timestamp: time::OffsetDateTime::now_utc(), + } + } +} diff --git a/cdevents-sdk/src/error.rs b/cdevents-sdk/src/error.rs new file mode 100644 index 0000000..51ac340 --- /dev/null +++ b/cdevents-sdk/src/error.rs @@ -0,0 +1,17 @@ +use thiserror::Error; + +// type Result = std::result::Result; + +#[derive(Error, Debug)] +pub enum Error { + #[error("Empty data in cloudevent")] + DataNotFoundInCloudEvent, + #[error(transparent)] + UriParseError( #[from] fluent_uri::ParseError), + #[error(transparent)] + SerdeJsonError( #[from] serde_json::Error), + #[error("unknown error")] + Unknown, + #[error("{0} should be non-empty")] + EmptyString(&'static str) +} diff --git a/cdevents-sdk/src/generated/artifact_packaged.rs b/cdevents-sdk/src/generated/artifact_packaged.rs new file mode 100644 index 0000000..e4472a7 --- /dev/null +++ b/cdevents-sdk/src/generated/artifact_packaged.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "change",)] + pub change: ContentChange, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentChange { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/artifact_published.rs b/cdevents-sdk/src/generated/artifact_published.rs new file mode 100644 index 0000000..c1162a8 --- /dev/null +++ b/cdevents-sdk/src/generated/artifact_published.rs @@ -0,0 +1,27 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/artifact_signed.rs b/cdevents-sdk/src/generated/artifact_signed.rs new file mode 100644 index 0000000..b7b700e --- /dev/null +++ b/cdevents-sdk/src/generated/artifact_signed.rs @@ -0,0 +1,29 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "signature",)] + pub signature: String, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/branch_created.rs b/cdevents-sdk/src/generated/branch_created.rs new file mode 100644 index 0000000..99f44c3 --- /dev/null +++ b/cdevents-sdk/src/generated/branch_created.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "repository", default, skip_serializing_if = "Option::is_none",)] + pub repository: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentRepository { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/branch_deleted.rs b/cdevents-sdk/src/generated/branch_deleted.rs new file mode 100644 index 0000000..99f44c3 --- /dev/null +++ b/cdevents-sdk/src/generated/branch_deleted.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "repository", default, skip_serializing_if = "Option::is_none",)] + pub repository: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentRepository { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/build_finished.rs b/cdevents-sdk/src/generated/build_finished.rs new file mode 100644 index 0000000..ed7d960 --- /dev/null +++ b/cdevents-sdk/src/generated/build_finished.rs @@ -0,0 +1,29 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "artifactId", default, skip_serializing_if = "Option::is_none",)] + pub artifact_id: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/build_queued.rs b/cdevents-sdk/src/generated/build_queued.rs new file mode 100644 index 0000000..c1162a8 --- /dev/null +++ b/cdevents-sdk/src/generated/build_queued.rs @@ -0,0 +1,27 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/build_started.rs b/cdevents-sdk/src/generated/build_started.rs new file mode 100644 index 0000000..c1162a8 --- /dev/null +++ b/cdevents-sdk/src/generated/build_started.rs @@ -0,0 +1,27 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/change_abandoned.rs b/cdevents-sdk/src/generated/change_abandoned.rs new file mode 100644 index 0000000..99f44c3 --- /dev/null +++ b/cdevents-sdk/src/generated/change_abandoned.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "repository", default, skip_serializing_if = "Option::is_none",)] + pub repository: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentRepository { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/change_created.rs b/cdevents-sdk/src/generated/change_created.rs new file mode 100644 index 0000000..99f44c3 --- /dev/null +++ b/cdevents-sdk/src/generated/change_created.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "repository", default, skip_serializing_if = "Option::is_none",)] + pub repository: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentRepository { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/change_merged.rs b/cdevents-sdk/src/generated/change_merged.rs new file mode 100644 index 0000000..99f44c3 --- /dev/null +++ b/cdevents-sdk/src/generated/change_merged.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "repository", default, skip_serializing_if = "Option::is_none",)] + pub repository: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentRepository { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/change_reviewed.rs b/cdevents-sdk/src/generated/change_reviewed.rs new file mode 100644 index 0000000..99f44c3 --- /dev/null +++ b/cdevents-sdk/src/generated/change_reviewed.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "repository", default, skip_serializing_if = "Option::is_none",)] + pub repository: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentRepository { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/change_updated.rs b/cdevents-sdk/src/generated/change_updated.rs new file mode 100644 index 0000000..99f44c3 --- /dev/null +++ b/cdevents-sdk/src/generated/change_updated.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "repository", default, skip_serializing_if = "Option::is_none",)] + pub repository: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentRepository { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/environment_created.rs b/cdevents-sdk/src/generated/environment_created.rs new file mode 100644 index 0000000..804f4be --- /dev/null +++ b/cdevents-sdk/src/generated/environment_created.rs @@ -0,0 +1,31 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/environment_deleted.rs b/cdevents-sdk/src/generated/environment_deleted.rs new file mode 100644 index 0000000..a10c7d6 --- /dev/null +++ b/cdevents-sdk/src/generated/environment_deleted.rs @@ -0,0 +1,29 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/environment_modified.rs b/cdevents-sdk/src/generated/environment_modified.rs new file mode 100644 index 0000000..804f4be --- /dev/null +++ b/cdevents-sdk/src/generated/environment_modified.rs @@ -0,0 +1,31 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/incident_detected.rs b/cdevents-sdk/src/generated/incident_detected.rs new file mode 100644 index 0000000..303f33b --- /dev/null +++ b/cdevents-sdk/src/generated/incident_detected.rs @@ -0,0 +1,55 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "artifactId", default, skip_serializing_if = "Option::is_none",)] + pub artifact_id: Option, + #[serde(rename = "description", default, skip_serializing_if = "Option::is_none",)] + pub description: Option, + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "service", default, skip_serializing_if = "Option::is_none",)] + pub service: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentService { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/incident_reported.rs b/cdevents-sdk/src/generated/incident_reported.rs new file mode 100644 index 0000000..a4ac0c1 --- /dev/null +++ b/cdevents-sdk/src/generated/incident_reported.rs @@ -0,0 +1,57 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "artifactId", default, skip_serializing_if = "Option::is_none",)] + pub artifact_id: Option, + #[serde(rename = "description", default, skip_serializing_if = "Option::is_none",)] + pub description: Option, + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "service", default, skip_serializing_if = "Option::is_none",)] + pub service: Option, + #[serde(rename = "ticketURI",)] + pub ticket_uri: crate::Uri, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentService { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/incident_resolved.rs b/cdevents-sdk/src/generated/incident_resolved.rs new file mode 100644 index 0000000..303f33b --- /dev/null +++ b/cdevents-sdk/src/generated/incident_resolved.rs @@ -0,0 +1,55 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "artifactId", default, skip_serializing_if = "Option::is_none",)] + pub artifact_id: Option, + #[serde(rename = "description", default, skip_serializing_if = "Option::is_none",)] + pub description: Option, + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "service", default, skip_serializing_if = "Option::is_none",)] + pub service: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentService { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/mod.rs b/cdevents-sdk/src/generated/mod.rs new file mode 100644 index 0000000..47f92f2 --- /dev/null +++ b/cdevents-sdk/src/generated/mod.rs @@ -0,0 +1,811 @@ +// @generated +// by cdevents/sdk-rust/generator (mod.hbs) + +use serde::de::Error; + +pub mod artifact_packaged; +pub mod artifact_published; +pub mod artifact_signed; +pub mod branch_created; +pub mod branch_deleted; +pub mod build_finished; +pub mod build_queued; +pub mod build_started; +pub mod change_abandoned; +pub mod change_created; +pub mod change_merged; +pub mod change_reviewed; +pub mod change_updated; +pub mod environment_created; +pub mod environment_deleted; +pub mod environment_modified; +pub mod incident_detected; +pub mod incident_reported; +pub mod incident_resolved; +pub mod pipelinerun_finished; +pub mod pipelinerun_queued; +pub mod pipelinerun_started; +pub mod repository_created; +pub mod repository_deleted; +pub mod repository_modified; +pub mod service_deployed; +pub mod service_published; +pub mod service_removed; +pub mod service_rolledback; +pub mod service_upgraded; +pub mod taskrun_finished; +pub mod taskrun_started; +pub mod testcaserun_finished; +pub mod testcaserun_queued; +pub mod testcaserun_started; +pub mod testoutput_published; +pub mod testsuiterun_finished; +pub mod testsuiterun_queued; +pub mod testsuiterun_started; + +use serde::{Serialize, Deserialize}; + +pub const ARTIFACT_PACKAGED: &str = "dev.cdevents.artifact.packaged.0.1.1"; +pub const ARTIFACT_PUBLISHED: &str = "dev.cdevents.artifact.published.0.1.1"; +pub const ARTIFACT_SIGNED: &str = "dev.cdevents.artifact.signed.0.1.0"; +pub const BRANCH_CREATED: &str = "dev.cdevents.branch.created.0.1.2"; +pub const BRANCH_DELETED: &str = "dev.cdevents.branch.deleted.0.1.2"; +pub const BUILD_FINISHED: &str = "dev.cdevents.build.finished.0.1.1"; +pub const BUILD_QUEUED: &str = "dev.cdevents.build.queued.0.1.1"; +pub const BUILD_STARTED: &str = "dev.cdevents.build.started.0.1.1"; +pub const CHANGE_ABANDONED: &str = "dev.cdevents.change.abandoned.0.1.2"; +pub const CHANGE_CREATED: &str = "dev.cdevents.change.created.0.1.2"; +pub const CHANGE_MERGED: &str = "dev.cdevents.change.merged.0.1.2"; +pub const CHANGE_REVIEWED: &str = "dev.cdevents.change.reviewed.0.1.2"; +pub const CHANGE_UPDATED: &str = "dev.cdevents.change.updated.0.1.2"; +pub const ENVIRONMENT_CREATED: &str = "dev.cdevents.environment.created.0.1.1"; +pub const ENVIRONMENT_DELETED: &str = "dev.cdevents.environment.deleted.0.1.1"; +pub const ENVIRONMENT_MODIFIED: &str = "dev.cdevents.environment.modified.0.1.1"; +pub const INCIDENT_DETECTED: &str = "dev.cdevents.incident.detected.0.1.0"; +pub const INCIDENT_REPORTED: &str = "dev.cdevents.incident.reported.0.1.0"; +pub const INCIDENT_RESOLVED: &str = "dev.cdevents.incident.resolved.0.1.0"; +pub const PIPELINERUN_FINISHED: &str = "dev.cdevents.pipelinerun.finished.0.1.1"; +pub const PIPELINERUN_QUEUED: &str = "dev.cdevents.pipelinerun.queued.0.1.1"; +pub const PIPELINERUN_STARTED: &str = "dev.cdevents.pipelinerun.started.0.1.1"; +pub const REPOSITORY_CREATED: &str = "dev.cdevents.repository.created.0.1.1"; +pub const REPOSITORY_DELETED: &str = "dev.cdevents.repository.deleted.0.1.1"; +pub const REPOSITORY_MODIFIED: &str = "dev.cdevents.repository.modified.0.1.1"; +pub const SERVICE_DEPLOYED: &str = "dev.cdevents.service.deployed.0.1.1"; +pub const SERVICE_PUBLISHED: &str = "dev.cdevents.service.published.0.1.1"; +pub const SERVICE_REMOVED: &str = "dev.cdevents.service.removed.0.1.1"; +pub const SERVICE_ROLLEDBACK: &str = "dev.cdevents.service.rolledback.0.1.1"; +pub const SERVICE_UPGRADED: &str = "dev.cdevents.service.upgraded.0.1.1"; +pub const TASKRUN_FINISHED: &str = "dev.cdevents.taskrun.finished.0.1.1"; +pub const TASKRUN_STARTED: &str = "dev.cdevents.taskrun.started.0.1.1"; +pub const TESTCASERUN_FINISHED: &str = "dev.cdevents.testcaserun.finished.0.1.0"; +pub const TESTCASERUN_QUEUED: &str = "dev.cdevents.testcaserun.queued.0.1.0"; +pub const TESTCASERUN_STARTED: &str = "dev.cdevents.testcaserun.started.0.1.0"; +pub const TESTOUTPUT_PUBLISHED: &str = "dev.cdevents.testoutput.published.0.1.0"; +pub const TESTSUITERUN_FINISHED: &str = "dev.cdevents.testsuiterun.finished.0.1.0"; +pub const TESTSUITERUN_QUEUED: &str = "dev.cdevents.testsuiterun.queued.0.1.0"; +pub const TESTSUITERUN_STARTED: &str = "dev.cdevents.testsuiterun.started.0.1.0"; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(untagged)] // TODO how to use content of context.type as discriminator ? +pub enum Content { + ArtifactPackaged(artifact_packaged::Content), + ArtifactPublished(artifact_published::Content), + ArtifactSigned(artifact_signed::Content), + BranchCreated(branch_created::Content), + BranchDeleted(branch_deleted::Content), + BuildFinished(build_finished::Content), + BuildQueued(build_queued::Content), + BuildStarted(build_started::Content), + ChangeAbandoned(change_abandoned::Content), + ChangeCreated(change_created::Content), + ChangeMerged(change_merged::Content), + ChangeReviewed(change_reviewed::Content), + ChangeUpdated(change_updated::Content), + EnvironmentCreated(environment_created::Content), + EnvironmentDeleted(environment_deleted::Content), + EnvironmentModified(environment_modified::Content), + IncidentDetected(incident_detected::Content), + IncidentReported(incident_reported::Content), + IncidentResolved(incident_resolved::Content), + PipelinerunFinished(pipelinerun_finished::Content), + PipelinerunQueued(pipelinerun_queued::Content), + PipelinerunStarted(pipelinerun_started::Content), + RepositoryCreated(repository_created::Content), + RepositoryDeleted(repository_deleted::Content), + RepositoryModified(repository_modified::Content), + ServiceDeployed(service_deployed::Content), + ServicePublished(service_published::Content), + ServiceRemoved(service_removed::Content), + ServiceRolledback(service_rolledback::Content), + ServiceUpgraded(service_upgraded::Content), + TaskrunFinished(taskrun_finished::Content), + TaskrunStarted(taskrun_started::Content), + TestcaserunFinished(testcaserun_finished::Content), + TestcaserunQueued(testcaserun_queued::Content), + TestcaserunStarted(testcaserun_started::Content), + TestoutputPublished(testoutput_published::Content), + TestsuiterunFinished(testsuiterun_finished::Content), + TestsuiterunQueued(testsuiterun_queued::Content), + TestsuiterunStarted(testsuiterun_started::Content), +} + +impl Content { + pub fn from_json(ty: &str, json: serde_json::Value) -> Result{ + match ty { + ARTIFACT_PACKAGED => { + let variant: artifact_packaged::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + ARTIFACT_PUBLISHED => { + let variant: artifact_published::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + ARTIFACT_SIGNED => { + let variant: artifact_signed::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + BRANCH_CREATED => { + let variant: branch_created::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + BRANCH_DELETED => { + let variant: branch_deleted::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + BUILD_FINISHED => { + let variant: build_finished::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + BUILD_QUEUED => { + let variant: build_queued::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + BUILD_STARTED => { + let variant: build_started::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + CHANGE_ABANDONED => { + let variant: change_abandoned::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + CHANGE_CREATED => { + let variant: change_created::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + CHANGE_MERGED => { + let variant: change_merged::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + CHANGE_REVIEWED => { + let variant: change_reviewed::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + CHANGE_UPDATED => { + let variant: change_updated::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + ENVIRONMENT_CREATED => { + let variant: environment_created::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + ENVIRONMENT_DELETED => { + let variant: environment_deleted::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + ENVIRONMENT_MODIFIED => { + let variant: environment_modified::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + INCIDENT_DETECTED => { + let variant: incident_detected::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + INCIDENT_REPORTED => { + let variant: incident_reported::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + INCIDENT_RESOLVED => { + let variant: incident_resolved::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + PIPELINERUN_FINISHED => { + let variant: pipelinerun_finished::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + PIPELINERUN_QUEUED => { + let variant: pipelinerun_queued::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + PIPELINERUN_STARTED => { + let variant: pipelinerun_started::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + REPOSITORY_CREATED => { + let variant: repository_created::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + REPOSITORY_DELETED => { + let variant: repository_deleted::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + REPOSITORY_MODIFIED => { + let variant: repository_modified::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + SERVICE_DEPLOYED => { + let variant: service_deployed::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + SERVICE_PUBLISHED => { + let variant: service_published::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + SERVICE_REMOVED => { + let variant: service_removed::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + SERVICE_ROLLEDBACK => { + let variant: service_rolledback::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + SERVICE_UPGRADED => { + let variant: service_upgraded::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TASKRUN_FINISHED => { + let variant: taskrun_finished::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TASKRUN_STARTED => { + let variant: taskrun_started::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TESTCASERUN_FINISHED => { + let variant: testcaserun_finished::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TESTCASERUN_QUEUED => { + let variant: testcaserun_queued::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TESTCASERUN_STARTED => { + let variant: testcaserun_started::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TESTOUTPUT_PUBLISHED => { + let variant: testoutput_published::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TESTSUITERUN_FINISHED => { + let variant: testsuiterun_finished::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TESTSUITERUN_QUEUED => { + let variant: testsuiterun_queued::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + TESTSUITERUN_STARTED => { + let variant: testsuiterun_started::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + variant => Err(serde_json::Error::custom(format_args!( + "unknown variant `{}`, expected 'dev.cdevents.{{subject}}.{{predicate}}.{{version}}'", + variant, + ))), + } + } + + 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(&self) -> &'static str { + match self { + Self::ArtifactPackaged(_) => "artifact", + Self::ArtifactPublished(_) => "artifact", + Self::ArtifactSigned(_) => "artifact", + Self::BranchCreated(_) => "branch", + Self::BranchDeleted(_) => "branch", + Self::BuildFinished(_) => "build", + Self::BuildQueued(_) => "build", + Self::BuildStarted(_) => "build", + Self::ChangeAbandoned(_) => "change", + Self::ChangeCreated(_) => "change", + Self::ChangeMerged(_) => "change", + Self::ChangeReviewed(_) => "change", + Self::ChangeUpdated(_) => "change", + Self::EnvironmentCreated(_) => "environment", + Self::EnvironmentDeleted(_) => "environment", + Self::EnvironmentModified(_) => "environment", + Self::IncidentDetected(_) => "incident", + Self::IncidentReported(_) => "incident", + Self::IncidentResolved(_) => "incident", + Self::PipelinerunFinished(_) => "pipelineRun", + Self::PipelinerunQueued(_) => "pipelineRun", + Self::PipelinerunStarted(_) => "pipelineRun", + Self::RepositoryCreated(_) => "repository", + Self::RepositoryDeleted(_) => "repository", + Self::RepositoryModified(_) => "repository", + Self::ServiceDeployed(_) => "service", + Self::ServicePublished(_) => "service", + Self::ServiceRemoved(_) => "service", + Self::ServiceRolledback(_) => "service", + Self::ServiceUpgraded(_) => "service", + Self::TaskrunFinished(_) => "taskRun", + Self::TaskrunStarted(_) => "taskRun", + Self::TestcaserunFinished(_) => "testCaseRun", + Self::TestcaserunQueued(_) => "testCaseRun", + Self::TestcaserunStarted(_) => "testCaseRun", + Self::TestoutputPublished(_) => "testOutput", + Self::TestsuiterunFinished(_) => "testSuiteRun", + Self::TestsuiterunQueued(_) => "testSuiteRun", + Self::TestsuiterunStarted(_) => "testSuiteRun", + } + } + + pub fn predicate(&self) -> &'static str { + match self { + Self::ArtifactPackaged(_) => "packaged", + Self::ArtifactPublished(_) => "published", + Self::ArtifactSigned(_) => "signed", + Self::BranchCreated(_) => "created", + Self::BranchDeleted(_) => "deleted", + Self::BuildFinished(_) => "finished", + Self::BuildQueued(_) => "queued", + Self::BuildStarted(_) => "started", + Self::ChangeAbandoned(_) => "abandoned", + Self::ChangeCreated(_) => "created", + Self::ChangeMerged(_) => "merged", + Self::ChangeReviewed(_) => "reviewed", + Self::ChangeUpdated(_) => "updated", + Self::EnvironmentCreated(_) => "created", + Self::EnvironmentDeleted(_) => "deleted", + Self::EnvironmentModified(_) => "modified", + Self::IncidentDetected(_) => "detected", + Self::IncidentReported(_) => "reported", + Self::IncidentResolved(_) => "resolved", + Self::PipelinerunFinished(_) => "finished", + Self::PipelinerunQueued(_) => "queued", + Self::PipelinerunStarted(_) => "started", + Self::RepositoryCreated(_) => "created", + Self::RepositoryDeleted(_) => "deleted", + Self::RepositoryModified(_) => "modified", + Self::ServiceDeployed(_) => "deployed", + Self::ServicePublished(_) => "published", + Self::ServiceRemoved(_) => "removed", + Self::ServiceRolledback(_) => "rolledback", + Self::ServiceUpgraded(_) => "upgraded", + Self::TaskrunFinished(_) => "finished", + Self::TaskrunStarted(_) => "started", + Self::TestcaserunFinished(_) => "finished", + Self::TestcaserunQueued(_) => "queued", + Self::TestcaserunStarted(_) => "started", + Self::TestoutputPublished(_) => "published", + Self::TestsuiterunFinished(_) => "finished", + Self::TestsuiterunQueued(_) => "queued", + Self::TestsuiterunStarted(_) => "started", + } + } +} + +// due to inconstency in case/format the subject could be not be extracted from the context.type (ty), jsonshema $id, spec filename (shema, examples) +pub fn extract_subject_predicate(ty: &str) -> Option<(&str, &str)>{ + // let mut split = ty.split('.'); + match ty { + ARTIFACT_PACKAGED => Some(("artifact", "packaged")), + ARTIFACT_PUBLISHED => Some(("artifact", "published")), + ARTIFACT_SIGNED => Some(("artifact", "signed")), + BRANCH_CREATED => Some(("branch", "created")), + BRANCH_DELETED => Some(("branch", "deleted")), + BUILD_FINISHED => Some(("build", "finished")), + BUILD_QUEUED => Some(("build", "queued")), + BUILD_STARTED => Some(("build", "started")), + CHANGE_ABANDONED => Some(("change", "abandoned")), + CHANGE_CREATED => Some(("change", "created")), + CHANGE_MERGED => Some(("change", "merged")), + CHANGE_REVIEWED => Some(("change", "reviewed")), + CHANGE_UPDATED => Some(("change", "updated")), + ENVIRONMENT_CREATED => Some(("environment", "created")), + ENVIRONMENT_DELETED => Some(("environment", "deleted")), + ENVIRONMENT_MODIFIED => Some(("environment", "modified")), + INCIDENT_DETECTED => Some(("incident", "detected")), + INCIDENT_REPORTED => Some(("incident", "reported")), + INCIDENT_RESOLVED => Some(("incident", "resolved")), + PIPELINERUN_FINISHED => Some(("pipelineRun", "finished")), + PIPELINERUN_QUEUED => Some(("pipelineRun", "queued")), + PIPELINERUN_STARTED => Some(("pipelineRun", "started")), + REPOSITORY_CREATED => Some(("repository", "created")), + REPOSITORY_DELETED => Some(("repository", "deleted")), + REPOSITORY_MODIFIED => Some(("repository", "modified")), + SERVICE_DEPLOYED => Some(("service", "deployed")), + SERVICE_PUBLISHED => Some(("service", "published")), + SERVICE_REMOVED => Some(("service", "removed")), + SERVICE_ROLLEDBACK => Some(("service", "rolledback")), + SERVICE_UPGRADED => Some(("service", "upgraded")), + TASKRUN_FINISHED => Some(("taskRun", "finished")), + TASKRUN_STARTED => Some(("taskRun", "started")), + TESTCASERUN_FINISHED => Some(("testCaseRun", "finished")), + TESTCASERUN_QUEUED => Some(("testCaseRun", "queued")), + TESTCASERUN_STARTED => Some(("testCaseRun", "started")), + TESTOUTPUT_PUBLISHED => Some(("testOutput", "published")), + TESTSUITERUN_FINISHED => Some(("testSuiteRun", "finished")), + TESTSUITERUN_QUEUED => Some(("testSuiteRun", "queued")), + TESTSUITERUN_STARTED => Some(("testSuiteRun", "started")), + _ => None, + } +} + +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) + } +} + +#[cfg(feature = "testkit")] +impl<> proptest::arbitrary::Arbitrary for Content { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::prelude::*; + prop_oneof![ + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + any::().prop_map(Content::from), + ].boxed() + } +} + +// #[cfg(test)] +// mod tests { +// use super::*; +// +// #[test] +// fn test_true() { +// +// assert_eq!(extract_subject_predicate(ARTIFACT_PACKAGED), Some(("artifact","packaged"))); +// +// assert_eq!(extract_subject_predicate(ARTIFACT_PUBLISHED), Some(("artifact","published"))); +// +// assert_eq!(extract_subject_predicate(ARTIFACT_SIGNED), Some(("artifact","signed"))); +// +// assert_eq!(extract_subject_predicate(BRANCH_CREATED), Some(("branch","created"))); +// +// assert_eq!(extract_subject_predicate(BRANCH_DELETED), Some(("branch","deleted"))); +// +// assert_eq!(extract_subject_predicate(BUILD_FINISHED), Some(("build","finished"))); +// +// assert_eq!(extract_subject_predicate(BUILD_QUEUED), Some(("build","queued"))); +// +// assert_eq!(extract_subject_predicate(BUILD_STARTED), Some(("build","started"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_ABANDONED), Some(("change","abandoned"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_CREATED), Some(("change","created"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_MERGED), Some(("change","merged"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_REVIEWED), Some(("change","reviewed"))); +// +// assert_eq!(extract_subject_predicate(CHANGE_UPDATED), Some(("change","updated"))); +// +// assert_eq!(extract_subject_predicate(ENVIRONMENT_CREATED), Some(("environment","created"))); +// +// assert_eq!(extract_subject_predicate(ENVIRONMENT_DELETED), Some(("environment","deleted"))); +// +// assert_eq!(extract_subject_predicate(ENVIRONMENT_MODIFIED), Some(("environment","modified"))); +// +// assert_eq!(extract_subject_predicate(INCIDENT_DETECTED), Some(("incident","detected"))); +// +// assert_eq!(extract_subject_predicate(INCIDENT_REPORTED), Some(("incident","reported"))); +// +// assert_eq!(extract_subject_predicate(INCIDENT_RESOLVED), Some(("incident","resolved"))); +// +// assert_eq!(extract_subject_predicate(PIPELINERUN_FINISHED), Some(("pipelineRun","finished"))); +// +// assert_eq!(extract_subject_predicate(PIPELINERUN_QUEUED), Some(("pipelineRun","queued"))); +// +// assert_eq!(extract_subject_predicate(PIPELINERUN_STARTED), Some(("pipelineRun","started"))); +// +// assert_eq!(extract_subject_predicate(REPOSITORY_CREATED), Some(("repository","created"))); +// +// assert_eq!(extract_subject_predicate(REPOSITORY_DELETED), Some(("repository","deleted"))); +// +// assert_eq!(extract_subject_predicate(REPOSITORY_MODIFIED), Some(("repository","modified"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_DEPLOYED), Some(("service","deployed"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_PUBLISHED), Some(("service","published"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_REMOVED), Some(("service","removed"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_ROLLEDBACK), Some(("service","rolledback"))); +// +// assert_eq!(extract_subject_predicate(SERVICE_UPGRADED), Some(("service","upgraded"))); +// +// assert_eq!(extract_subject_predicate(TASKRUN_FINISHED), Some(("taskRun","finished"))); +// +// assert_eq!(extract_subject_predicate(TASKRUN_STARTED), Some(("taskRun","started"))); +// +// assert_eq!(extract_subject_predicate(TESTCASERUN_FINISHED), Some(("testCaseRun","finished"))); +// +// assert_eq!(extract_subject_predicate(TESTCASERUN_QUEUED), Some(("testCaseRun","queued"))); +// +// assert_eq!(extract_subject_predicate(TESTCASERUN_STARTED), Some(("testCaseRun","started"))); +// +// assert_eq!(extract_subject_predicate(TESTOUTPUT_PUBLISHED), Some(("testOutput","published"))); +// +// assert_eq!(extract_subject_predicate(TESTSUITERUN_FINISHED), Some(("testSuiteRun","finished"))); +// +// assert_eq!(extract_subject_predicate(TESTSUITERUN_QUEUED), Some(("testSuiteRun","queued"))); +// +// assert_eq!(extract_subject_predicate(TESTSUITERUN_STARTED), Some(("testSuiteRun","started"))); +// +// } +// } \ No newline at end of file diff --git a/cdevents-sdk/src/generated/pipelinerun_finished.rs b/cdevents-sdk/src/generated/pipelinerun_finished.rs new file mode 100644 index 0000000..7839d5e --- /dev/null +++ b/cdevents-sdk/src/generated/pipelinerun_finished.rs @@ -0,0 +1,35 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "errors", default, skip_serializing_if = "Option::is_none",)] + pub errors: Option, + #[serde(rename = "outcome", default, skip_serializing_if = "Option::is_none",)] + pub outcome: Option, + #[serde(rename = "pipelineName", default, skip_serializing_if = "Option::is_none",)] + pub pipeline_name: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/pipelinerun_queued.rs b/cdevents-sdk/src/generated/pipelinerun_queued.rs new file mode 100644 index 0000000..5f42f00 --- /dev/null +++ b/cdevents-sdk/src/generated/pipelinerun_queued.rs @@ -0,0 +1,31 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "pipelineName", default, skip_serializing_if = "Option::is_none",)] + pub pipeline_name: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/pipelinerun_started.rs b/cdevents-sdk/src/generated/pipelinerun_started.rs new file mode 100644 index 0000000..3270b0a --- /dev/null +++ b/cdevents-sdk/src/generated/pipelinerun_started.rs @@ -0,0 +1,31 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "pipelineName",)] + pub pipeline_name: String, + #[serde(rename = "url",)] + pub url: String, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/repository_created.rs b/cdevents-sdk/src/generated/repository_created.rs new file mode 100644 index 0000000..b2d8e60 --- /dev/null +++ b/cdevents-sdk/src/generated/repository_created.rs @@ -0,0 +1,35 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "name",)] + pub name: crate::Name, + #[serde(rename = "owner", default, skip_serializing_if = "Option::is_none",)] + pub owner: Option, + #[serde(rename = "url",)] + pub url: String, + #[serde(rename = "viewUrl", default, skip_serializing_if = "Option::is_none",)] + pub view_url: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/repository_deleted.rs b/cdevents-sdk/src/generated/repository_deleted.rs new file mode 100644 index 0000000..0fa5c4d --- /dev/null +++ b/cdevents-sdk/src/generated/repository_deleted.rs @@ -0,0 +1,35 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "owner", default, skip_serializing_if = "Option::is_none",)] + pub owner: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, + #[serde(rename = "viewUrl", default, skip_serializing_if = "Option::is_none",)] + pub view_url: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/repository_modified.rs b/cdevents-sdk/src/generated/repository_modified.rs new file mode 100644 index 0000000..0fa5c4d --- /dev/null +++ b/cdevents-sdk/src/generated/repository_modified.rs @@ -0,0 +1,35 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "owner", default, skip_serializing_if = "Option::is_none",)] + pub owner: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, + #[serde(rename = "viewUrl", default, skip_serializing_if = "Option::is_none",)] + pub view_url: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/service_deployed.rs b/cdevents-sdk/src/generated/service_deployed.rs new file mode 100644 index 0000000..b9fe280 --- /dev/null +++ b/cdevents-sdk/src/generated/service_deployed.rs @@ -0,0 +1,41 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "artifactId",)] + pub artifact_id: crate::Id, + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/service_published.rs b/cdevents-sdk/src/generated/service_published.rs new file mode 100644 index 0000000..e458076 --- /dev/null +++ b/cdevents-sdk/src/generated/service_published.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment", default, skip_serializing_if = "Option::is_none",)] + pub environment: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/service_removed.rs b/cdevents-sdk/src/generated/service_removed.rs new file mode 100644 index 0000000..e458076 --- /dev/null +++ b/cdevents-sdk/src/generated/service_removed.rs @@ -0,0 +1,39 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment", default, skip_serializing_if = "Option::is_none",)] + pub environment: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/service_rolledback.rs b/cdevents-sdk/src/generated/service_rolledback.rs new file mode 100644 index 0000000..b9fe280 --- /dev/null +++ b/cdevents-sdk/src/generated/service_rolledback.rs @@ -0,0 +1,41 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "artifactId",)] + pub artifact_id: crate::Id, + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/service_upgraded.rs b/cdevents-sdk/src/generated/service_upgraded.rs new file mode 100644 index 0000000..b9fe280 --- /dev/null +++ b/cdevents-sdk/src/generated/service_upgraded.rs @@ -0,0 +1,41 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "artifactId",)] + pub artifact_id: crate::Id, + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/taskrun_finished.rs b/cdevents-sdk/src/generated/taskrun_finished.rs new file mode 100644 index 0000000..d47c3f7 --- /dev/null +++ b/cdevents-sdk/src/generated/taskrun_finished.rs @@ -0,0 +1,47 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "errors", default, skip_serializing_if = "Option::is_none",)] + pub errors: Option, + #[serde(rename = "outcome", default, skip_serializing_if = "Option::is_none",)] + pub outcome: Option, + #[serde(rename = "pipelineRun", default, skip_serializing_if = "Option::is_none",)] + pub pipeline_run: Option, + #[serde(rename = "taskName", default, skip_serializing_if = "Option::is_none",)] + pub task_name: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentPipelineRun { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/taskrun_started.rs b/cdevents-sdk/src/generated/taskrun_started.rs new file mode 100644 index 0000000..3f76d68 --- /dev/null +++ b/cdevents-sdk/src/generated/taskrun_started.rs @@ -0,0 +1,43 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "pipelineRun", default, skip_serializing_if = "Option::is_none",)] + pub pipeline_run: Option, + #[serde(rename = "taskName", default, skip_serializing_if = "Option::is_none",)] + pub task_name: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentPipelineRun { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/testcaserun_finished.rs b/cdevents-sdk/src/generated/testcaserun_finished.rs new file mode 100644 index 0000000..c6d4414 --- /dev/null +++ b/cdevents-sdk/src/generated/testcaserun_finished.rs @@ -0,0 +1,122 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "outcome",)] + pub outcome: ContentOutcome, + #[serde(rename = "reason", default, skip_serializing_if = "Option::is_none",)] + pub reason: Option, + #[serde(rename = "severity", default, skip_serializing_if = "Option::is_none",)] + pub severity: Option, + #[serde(rename = "testCase", default, skip_serializing_if = "Option::is_none",)] + pub test_case: Option, + #[serde(rename = "testSuiteRun", default, skip_serializing_if = "Option::is_none",)] + pub test_suite_run: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestSuiteRun { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestCase { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] + 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",)] + pub version: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentOutcome { + #[serde(rename = "pass")] + Pass, + #[serde(rename = "fail")] + Fail, + #[serde(rename = "cancel")] + Cancel, + #[serde(rename = "error")] + Error, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentSeverity { + #[serde(rename = "low")] + Low, + #[serde(rename = "medium")] + Medium, + #[serde(rename = "high")] + High, + #[serde(rename = "critical")] + Critical, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentTestCaseType { + #[serde(rename = "performance")] + Performance, + #[serde(rename = "functional")] + Functional, + #[serde(rename = "unit")] + Unit, + #[serde(rename = "security")] + Security, + #[serde(rename = "compliance")] + Compliance, + #[serde(rename = "integration")] + Integration, + #[serde(rename = "e2e")] + E2E, + #[serde(rename = "other")] + Other, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/testcaserun_queued.rs b/cdevents-sdk/src/generated/testcaserun_queued.rs new file mode 100644 index 0000000..3c5c12c --- /dev/null +++ b/cdevents-sdk/src/generated/testcaserun_queued.rs @@ -0,0 +1,117 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "testCase", default, skip_serializing_if = "Option::is_none",)] + pub test_case: Option, + #[serde(rename = "testSuiteRun", default, skip_serializing_if = "Option::is_none",)] + pub test_suite_run: Option, + #[serde(rename = "trigger", default, skip_serializing_if = "Option::is_none",)] + pub trigger: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTrigger { + #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] + pub ty: Option, + #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] + pub uri: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestSuiteRun { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestCase { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] + 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",)] + pub version: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentTestCaseType { + #[serde(rename = "performance")] + Performance, + #[serde(rename = "functional")] + Functional, + #[serde(rename = "unit")] + Unit, + #[serde(rename = "security")] + Security, + #[serde(rename = "compliance")] + Compliance, + #[serde(rename = "integration")] + Integration, + #[serde(rename = "e2e")] + E2E, + #[serde(rename = "other")] + Other, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentTriggerType { + #[serde(rename = "manual")] + Manual, + #[serde(rename = "pipeline")] + Pipeline, + #[serde(rename = "event")] + Event, + #[serde(rename = "schedule")] + Schedule, + #[serde(rename = "other")] + Other, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/testcaserun_started.rs b/cdevents-sdk/src/generated/testcaserun_started.rs new file mode 100644 index 0000000..3c5c12c --- /dev/null +++ b/cdevents-sdk/src/generated/testcaserun_started.rs @@ -0,0 +1,117 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "testCase", default, skip_serializing_if = "Option::is_none",)] + pub test_case: Option, + #[serde(rename = "testSuiteRun", default, skip_serializing_if = "Option::is_none",)] + pub test_suite_run: Option, + #[serde(rename = "trigger", default, skip_serializing_if = "Option::is_none",)] + pub trigger: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTrigger { + #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] + pub ty: Option, + #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] + pub uri: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestSuiteRun { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestCase { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] + 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",)] + pub version: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentTestCaseType { + #[serde(rename = "performance")] + Performance, + #[serde(rename = "functional")] + Functional, + #[serde(rename = "unit")] + Unit, + #[serde(rename = "security")] + Security, + #[serde(rename = "compliance")] + Compliance, + #[serde(rename = "integration")] + Integration, + #[serde(rename = "e2e")] + E2E, + #[serde(rename = "other")] + Other, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentTriggerType { + #[serde(rename = "manual")] + Manual, + #[serde(rename = "pipeline")] + Pipeline, + #[serde(rename = "event")] + Event, + #[serde(rename = "schedule")] + Schedule, + #[serde(rename = "other")] + Other, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/testoutput_published.rs b/cdevents-sdk/src/generated/testoutput_published.rs new file mode 100644 index 0000000..b4a146a --- /dev/null +++ b/cdevents-sdk/src/generated/testoutput_published.rs @@ -0,0 +1,60 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "format",)] + pub format: String, + #[serde(rename = "outputType",)] + pub output_type: ContentOutputType, + #[serde(rename = "testCaseRun", default, skip_serializing_if = "Option::is_none",)] + pub test_case_run: Option, + #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] + pub uri: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestCaseRun { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentOutputType { + #[serde(rename = "report")] + Report, + #[serde(rename = "video")] + Video, + #[serde(rename = "image")] + Image, + #[serde(rename = "log")] + Log, + #[serde(rename = "other")] + Other, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/testsuiterun_finished.rs b/cdevents-sdk/src/generated/testsuiterun_finished.rs new file mode 100644 index 0000000..824bfb6 --- /dev/null +++ b/cdevents-sdk/src/generated/testsuiterun_finished.rs @@ -0,0 +1,87 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "outcome",)] + pub outcome: ContentOutcome, + #[serde(rename = "reason", default, skip_serializing_if = "Option::is_none",)] + pub reason: Option, + #[serde(rename = "severity", default, skip_serializing_if = "Option::is_none",)] + pub severity: Option, + #[serde(rename = "testSuite", default, skip_serializing_if = "Option::is_none",)] + pub test_suite: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestSuite { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] + pub uri: Option, + #[serde(rename = "version", default, skip_serializing_if = "Option::is_none",)] + pub version: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentOutcome { + #[serde(rename = "pass")] + Pass, + #[serde(rename = "fail")] + Fail, + #[serde(rename = "cancel")] + Cancel, + #[serde(rename = "error")] + Error, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentSeverity { + #[serde(rename = "low")] + Low, + #[serde(rename = "medium")] + Medium, + #[serde(rename = "high")] + High, + #[serde(rename = "critical")] + Critical, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/testsuiterun_queued.rs b/cdevents-sdk/src/generated/testsuiterun_queued.rs new file mode 100644 index 0000000..d5cae30 --- /dev/null +++ b/cdevents-sdk/src/generated/testsuiterun_queued.rs @@ -0,0 +1,82 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "testSuite", default, skip_serializing_if = "Option::is_none",)] + pub test_suite: Option, + #[serde(rename = "trigger", default, skip_serializing_if = "Option::is_none",)] + pub trigger: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTrigger { + #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] + pub ty: Option, + #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] + pub uri: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestSuite { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "url", default, skip_serializing_if = "Option::is_none",)] + pub url: Option, + #[serde(rename = "version", default, skip_serializing_if = "Option::is_none",)] + pub version: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentTriggerType { + #[serde(rename = "manual")] + Manual, + #[serde(rename = "pipeline")] + Pipeline, + #[serde(rename = "event")] + Event, + #[serde(rename = "schedule")] + Schedule, + #[serde(rename = "other")] + Other, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/generated/testsuiterun_started.rs b/cdevents-sdk/src/generated/testsuiterun_started.rs new file mode 100644 index 0000000..9c27a7d --- /dev/null +++ b/cdevents-sdk/src/generated/testsuiterun_started.rs @@ -0,0 +1,82 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct Content { + #[serde(rename = "environment",)] + pub environment: ContentEnvironment, + #[serde(rename = "testSuite", default, skip_serializing_if = "Option::is_none",)] + pub test_suite: Option, + #[serde(rename = "trigger", default, skip_serializing_if = "Option::is_none",)] + pub trigger: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTrigger { + #[serde(rename = "type", default, skip_serializing_if = "Option::is_none",)] + pub ty: Option, + #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] + pub uri: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentTestSuite { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "name", default, skip_serializing_if = "Option::is_none",)] + pub name: Option, + #[serde(rename = "uri", default, skip_serializing_if = "Option::is_none",)] + pub uri: Option, + #[serde(rename = "version", default, skip_serializing_if = "Option::is_none",)] + pub version: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct ContentEnvironment { + #[serde(rename = "id",)] + pub id: crate::Id, + #[serde(rename = "source", default, skip_serializing_if = "Option::is_none",)] + pub source: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum ContentTriggerType { + #[serde(rename = "manual")] + Manual, + #[serde(rename = "pipeline")] + Pipeline, + #[serde(rename = "event")] + Event, + #[serde(rename = "schedule")] + Schedule, + #[serde(rename = "other")] + Other, +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/id.rs b/cdevents-sdk/src/id.rs new file mode 100644 index 0000000..49e3d51 --- /dev/null +++ b/cdevents-sdk/src/id.rs @@ -0,0 +1,88 @@ +use std::{fmt::{Display, Formatter}, str::FromStr}; + +use serde::{Deserialize, Serialize}; + +pub type Id = NonEmptyString; +pub type Name = NonEmptyString; + +/// A non-empty string. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +pub struct NonEmptyString(String); + +impl NonEmptyString { + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +impl Default for NonEmptyString { + fn default() -> Self { + NonEmptyString("00000000-0000-0000-0000-000000000000".to_owned()) + } +} + +impl From for String { + fn from(id: NonEmptyString) -> Self { + id.0 + } +} +impl TryFrom for NonEmptyString { + type Error = crate::Error; + + fn try_from(value: String) -> Result { + if value.is_empty() { + return Err(crate::Error::EmptyString("id")) + } + Ok(Self(value)) + } +} + +impl TryFrom<&str> for NonEmptyString { + type Error = crate::Error; + + fn try_from(value: &str) -> Result { + if value.is_empty() { + return Err(crate::Error::EmptyString("id")) + } + Ok(Self(value.to_owned())) + } +} + +impl FromStr for NonEmptyString { + type Err = crate::Error; + + fn from_str(s: &str) -> Result { + Self::try_from(s) + } +} + +impl Display for NonEmptyString { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From<&NonEmptyString> for String { + fn from(id: &NonEmptyString) -> Self { + id.0.clone() + } +} + +impl AsRef for NonEmptyString { + fn as_ref(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "testkit")] +impl<> proptest::arbitrary::Arbitrary for NonEmptyString { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::prelude::*; + "\\PC+".prop_map(|id| + id.try_into().expect("generate valid id") + ).boxed() + } +} \ No newline at end of file diff --git a/cdevents-sdk/src/lib.rs b/cdevents-sdk/src/lib.rs new file mode 100644 index 0000000..76887c5 --- /dev/null +++ b/cdevents-sdk/src/lib.rs @@ -0,0 +1,24 @@ +#![doc = include_str!("../../README.md")] +//#![warn(missing_docs)] +// TODO remove unwrap(), expect(...) +// TODO reduce clone() +mod cdevent; +mod context; +#[cfg(feature = "cloudevents")] +pub mod cloudevents; +mod error; +mod generated; +mod id; +pub(crate) mod serde; +mod subject; +mod uri; +mod uri_reference; + +pub use cdevent::*; +pub use id::*; +pub(crate) use context::*; +pub use error::*; +pub use generated::*; +pub use subject::*; +pub use uri::*; +pub use uri_reference::*; diff --git a/cdevents-sdk/src/serde.rs b/cdevents-sdk/src/serde.rs new file mode 100644 index 0000000..e225c2f --- /dev/null +++ b/cdevents-sdk/src/serde.rs @@ -0,0 +1,46 @@ +// currently there is no generic way to handle Option +// 2 alertnatives: +// - write custom serializer +// - try to use the crate serde_with (serde_as) +// +// Creating, aliasing module with custom (de)serializer, +// also simplify the generation and introduce a small layer of abstraction/documentation. +// +// see [Using de/serialize\_with inside of an Option, Map, Vec ยท Issue #723 ยท serde-rs/serde](https://github.com/serde-rs/serde/issues/723) + +pub(crate) mod datetime { + use serde::{Deserializer, Serializer}; + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + time::serde::rfc3339::deserialize(deserializer) + } + + pub fn serialize(input: &time::OffsetDateTime, serializer: S) -> Result + where + S: Serializer, + { + time::serde::rfc3339::serialize(input, serializer) + } +} + +pub(crate) mod fluent_uri { + use serde::{de::Error, Deserialize, Deserializer, Serializer}; + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let txt = String::deserialize(deserializer)?; + fluent_uri::Uri::parse_from(txt).map_err(|e| D::Error::custom(e.1)) + } + + pub fn serialize(input: &fluent_uri::Uri, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_str(input.as_str()) + } +} diff --git a/cdevents-sdk/src/subject.rs b/cdevents-sdk/src/subject.rs new file mode 100644 index 0000000..f120a4f --- /dev/null +++ b/cdevents-sdk/src/subject.rs @@ -0,0 +1,130 @@ +use std::str::FromStr; + +use serde::{Deserialize, Serialize}; + +use crate::{Content, Id, UriReference}; + +/// see +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct Subject { + #[serde(rename = "content")] + content: Content, + #[serde(rename = "id")] + id: Id, + #[serde( + rename = "source", + default, + skip_serializing_if = "Option::is_none", + )] + source: Option, + #[serde(rename = "type")] + ty: String, +} + +impl Subject { + /// see + pub fn id(&self) -> &Id { + &self.id + } + + pub fn with_id(mut self, id: Id) -> Self { + self.id = id; + 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"))? + .try_into() + .map_err(serde::de::Error::custom)?, + ty: json["type"] + .as_str() + .ok_or_else(|| serde::de::Error::missing_field("type"))? + .to_string(), + source: match json["source"].as_str() { + None => None, + Some(s) => Some( + UriReference::from_str(s).map_err(serde::de::Error::custom)?, + ), + }, + content: Content::from_json(ty, json["content"].clone())?, + }) + } +} + +impl From for Subject where T: Into{ + fn from(content: T) -> Self { + let content = content.into(); + let ty = crate::extract_subject_predicate(content.ty()) + .map(|(s, _)| s) + .unwrap_or("unknown") + .to_owned(); + Self { + content, + id: Id::default(), + source: None, + ty, + } + } +} + +#[cfg(feature = "testkit")] +impl<> proptest::arbitrary::Arbitrary for Subject { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::prelude::*; + ( + any::(), + any::(), + any::>(), + ).prop_map(|(content, id, source)| { + let mut subject = Subject::from(content).with_id(id); + if let Some(source) = source { + subject = subject.with_source(source); + } + subject + }).boxed() + } +} + + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn jsonify_arbitraries(s in any::()) { + // Not enough information into json of subject to deserialize into the same sut content + // so only check that it could be serialized + serde_json::to_string(&s).unwrap(); + } + } +} \ No newline at end of file diff --git a/cdevents-sdk/src/uri.rs b/cdevents-sdk/src/uri.rs new file mode 100644 index 0000000..73cad0a --- /dev/null +++ b/cdevents-sdk/src/uri.rs @@ -0,0 +1,95 @@ +// wrapper for fluent_uri::Uri to allow for restristed set of operations +// and to complete currently missing features. +// Why fluent_uri? +// - support uri & uri-reference, preserve the original string, but young, doesn't impl PartialEq,... +// - http::Uri, more mature, but doesn't support uri-reference, and normalize url when generate string +//TODO impl the check difference for Uri and Uri-reference + +use std::str::FromStr; + +use serde::{Serialize, Deserialize}; +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use crate::UriReference; + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub struct Uri( + #[cfg_attr(feature = "testkit", proptest(value = "fluent_uri::Uri::parse_from(\"https://example.com/\".to_owned()).unwrap()"))] //TODO generate random value + #[serde(with = "crate::serde::fluent_uri")] + pub(crate) fluent_uri::Uri +); + +impl PartialEq for Uri { + fn eq(&self, other: &Self) -> bool { + self.0.as_str() == other.0.as_str() + } +} + +impl Eq for Uri {} + +impl FromStr for Uri { + type Err = crate::Error; + + fn from_str(s: &str) -> Result { + //TODO check it's not a reference URI + fluent_uri::Uri::parse_from(s.to_owned()).map_err(|(_,e)| e.into()).map(Uri) + } +} + +impl TryFrom for Uri { + type Error = crate::Error; + + fn try_from(s: UriReference) -> Result { + Uri::from_str(s.as_str()) + } +} + +impl TryFrom<&str> for Uri { + type Error = crate::Error; + + fn try_from(s: &str) -> Result { + fluent_uri::Uri::parse_from(s.to_owned()).map_err(|(_,e)| e.into()).map(Uri) + } +} + +impl TryFrom for Uri { + type Error = crate::Error; + + fn try_from(s: String) -> Result { + fluent_uri::Uri::parse_from(s).map_err(|(_,e)| e.into()).map(Uri) + } +} + +impl ToString for Uri { + fn to_string(&self) -> String { + self.0.as_str().to_owned()//into_string() + } +} + +impl Uri { + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +// impl From for fluent_uri::Uri { +// fn from(uri: Uri) -> Self { +// uri.0 +// } +// } + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/src/uri_reference.rs b/cdevents-sdk/src/uri_reference.rs new file mode 100644 index 0000000..11385ce --- /dev/null +++ b/cdevents-sdk/src/uri_reference.rs @@ -0,0 +1,98 @@ +use std::str::FromStr; + +use serde::{Serialize, Deserialize}; +use crate::Uri; + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct UriReference( + #[serde(with = "crate::serde::fluent_uri")] + pub(crate) fluent_uri::Uri +); + +impl PartialEq for UriReference { + fn eq(&self, other: &Self) -> bool { + self.0.as_str() == other.0.as_str() + } +} + +impl Eq for UriReference {} + +impl FromStr for UriReference { + type Err = crate::Error; + + fn from_str(s: &str) -> Result { + fluent_uri::Uri::parse_from(s.to_owned()).map_err(|(_,e)| e.into()).map(UriReference) + } +} + +impl TryFrom for UriReference { + type Error = crate::Error; + + fn try_from(s: Uri) -> Result { + Ok(UriReference(s.0)) + } +} + +impl TryFrom<&str> for UriReference { + type Error = crate::Error; + + fn try_from(s: &str) -> Result { + fluent_uri::Uri::parse_from(s.to_owned()).map_err(|(_,e)| e.into()).map(UriReference) + } +} + +impl TryFrom for UriReference { + type Error = crate::Error; + + fn try_from(s: String) -> Result { + fluent_uri::Uri::parse_from(s).map_err(|(_,e)| e.into()).map(UriReference) + } +} + +impl ToString for UriReference { + fn to_string(&self) -> String { + self.0.as_str().to_owned()//into_string() + } +} + +impl UriReference { + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +// impl From for fluent_uri::Uri { +// fn from(uri: UriReference) -> Self { +// uri.0 +// } +// } + +#[cfg(feature = "testkit")] +impl<> proptest::arbitrary::Arbitrary for UriReference { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::prelude::*; + (prop_oneof![ + "\\/[a-z_\\-\\/]+".prop_map(|s| UriReference::from_str(&s).unwrap()), + Just("https://example.com/").prop_map(|s| UriReference::from_str(s).unwrap()), + ]).boxed() + } +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/cdevents-sdk/tests/specs.rs b/cdevents-sdk/tests/specs.rs new file mode 100644 index 0000000..06cc5ec --- /dev/null +++ b/cdevents-sdk/tests/specs.rs @@ -0,0 +1,66 @@ +use assert_json_diff::assert_json_eq; +use cdevents_sdk::CDEvent; +use rstest::rstest; +use std::fs; +use std::path::PathBuf; +use proptest::prelude::*; +use boon::{Schemas, Compiler}; + +#[rstest] +fn for_each_example(#[files("../cdevents-spec/examples/*.json")] path: PathBuf) { + let example_txt = fs::read_to_string(path).expect("to read file as string"); + //HACK uri are stored ad http::Uri, they are "normalized" when serialized, so prenormalization to avoid failure like + // json atoms at path ".subject.content.repository.source" are not equal: + // lhs: + // "https://example.org" + // rhs: + // "https://example.org/" + // But it's not the case with fluent_uri::Uri + // + // example_txt = example_txt.replace("\"https://example.org\"", "\"https://example.org/\""); + + let example_json: serde_json::Value = + serde_json::from_str(&example_txt).expect("to parse as json"); + dbg!(&example_json); + let cdevent: CDEvent = + serde_json::from_value(example_json.clone()).expect("to parse as cdevent"); + dbg!(&cdevent); + let cdevent_json = serde_json::to_value(cdevent).expect("to convert into json"); + dbg!(&cdevent_json); + assert_json_eq!(example_json, cdevent_json); +} + +fn check_against_schema(json: &serde_json::Value, ty: &str) { + let (subject, predicate) = cdevents_sdk::extract_subject_predicate(ty).expect("valid type: {ty}"); + let schemapath = format!("../cdevents-spec/schemas/{subject}{predicate}.json").to_lowercase(); + //TODO optimize to not recompile a previously read schema + let mut schemas = Schemas::new(); + let mut compiler = Compiler::new(); + let sch_index = compiler.compile(&schemapath, &mut schemas); + if let Err(err) = sch_index { + panic!("{err:#}"); //like a assert(false,...) + } + let sch_index = sch_index.unwrap(); + let result = schemas.validate(json, sch_index); + if let Err(err) = result { + panic!("{err}"); + } +} + +#[rstest] +fn validate_example_against_schema(#[files("../cdevents-spec/examples/*.json")] path: PathBuf) { + let example_txt = fs::read_to_string(path).expect("to read file as string"); + let example_json: serde_json::Value = + serde_json::from_str(&example_txt).expect("to parse as json"); + let ty = example_json["context"]["type"].as_str().expect("valid context.type in json"); + check_against_schema(&example_json, ty); +} + +proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_check_jsonschema(s in any::()) { + let json = serde_json::to_value(&s).unwrap(); + check_against_schema(&json, s.ty()); + } +} diff --git a/cdevents-spec b/cdevents-spec new file mode 160000 index 0000000..2b63793 --- /dev/null +++ b/cdevents-spec @@ -0,0 +1 @@ +Subproject commit 2b63793165fa609d3a3b954ce71957209e79475e diff --git a/factory/Cargo.toml b/factory/Cargo.toml deleted file mode 100644 index f3f3fc4..0000000 --- a/factory/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "factory" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/factory/src/main.rs b/factory/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/factory/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/generator/Cargo.toml b/generator/Cargo.toml new file mode 100644 index 0000000..c66eb9d --- /dev/null +++ b/generator/Cargo.toml @@ -0,0 +1,23 @@ +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[package] +name = "generator" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +publish = false +repository.workspace = true +description = "generate cdevents type from json schema on cdevents-spec" + +[dependencies] +anyhow = "1.0" +clap = { version = "4", features = ["derive"] } +cruet = "0.14" +handlebars = { version = "5", features = ["dir_source"] } +handlebars_misc_helpers = { version = "0.15", default-features = false, features = [ + "string", + "json", +] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +url = "2.5" diff --git a/generator/README.md b/generator/README.md new file mode 100644 index 0000000..fe1efa0 --- /dev/null +++ b/generator/README.md @@ -0,0 +1,21 @@ +# cdevents rust code generator + +Goals: generate rust code for cdevents from jsonschema provided as part of cdevents specs. + +- The generator take read jsonschema as json apply them to a set of templates +- The generator is very basic (no json schema semantic, no `$ref` resolution) like [eventuallyconsultant/codegenr: Fast handlebars templates based code generator, ingesting swagger/openapi and other json/yaml documents with $refs, or graphql schema, outputs whatever you template](https://github.com/eventuallyconsultant/codegenr/) +- The generator is currently used to generated Subjects + +## Why not use a jsonschema to rust generator? + +- I tried some and they failed (no error), maybe too early, not support for the version of jsonschema used by cdevents (often they support jsonschema draft-4) +- The json schema (v0.3) are not connected, so lot of duplication (context,...), so classical generators will create as many Context type as Event type,... Our implementation only part of the schema is extracted to generate what is different aka the `content` of subjects. + +## Run + +To generate the `subjects` into sibling crate `cdevents/src/generated` from content of `cdevents-spec/schemas`, from root workspace + +```sh +cargo run -p generator -- --help +cargo run -p generator -- --templates-dir "generator/templates" --jsonschema-dir "cdevents-spec/schemas" --dest "cdevents-sdk/src/generated" +``` diff --git a/generator/src/main.rs b/generator/src/main.rs new file mode 100644 index 0000000..85e50fb --- /dev/null +++ b/generator/src/main.rs @@ -0,0 +1,284 @@ +use anyhow::{Context, Result}; +use clap::Parser; +use cruet::Inflector; +use handlebars::{DirectorySourceOptions, Handlebars}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use std::{fs, path::PathBuf}; + +/// generator of part of the rust code of cdevents from spec +#[derive(Parser, Debug)] +struct Settings { + /// directory with handlebars templates + #[arg(long, default_value = "templates")] + templates_dir: PathBuf, + + /// directory with json schemas of events to generate + #[arg(long, default_value = "../cdevents-spec/schemas")] + jsonschema_dir: PathBuf, + + /// destination directory where to generate code + #[arg(long, default_value = "../cdevents-sdk/src/generated")] + dest: PathBuf, +} + +fn main() -> Result<()> { + let settings = Settings::parse(); + + let mut hbs = Handlebars::new(); + hbs.set_strict_mode(true); + hbs.register_escape_fn(handlebars::no_escape); + //hbs.unregister_escape_fn(); + handlebars_misc_helpers::register(&mut hbs); + hbs.register_templates_directory(settings.templates_dir, DirectorySourceOptions::default())?; + + if settings.dest.exists() { + fs::remove_dir_all(&settings.dest)?; + } + fs::create_dir_all(&settings.dest)?; + + let mut variants = vec![]; + let mut jsonfiles = + std::fs::read_dir(settings.jsonschema_dir)?.collect::, _>>()?; + jsonfiles.sort_by_key(|v| v.file_name()); + for entry in jsonfiles { + let path = entry.path(); + if let Some(extension) = path.extension() { + if extension == "json" { + let json: Value = serde_json::from_str(&std::fs::read_to_string(&path)?)?; + let (variant_info, code) = generate_variant(&hbs, json) + .with_context(|| format!("failed to generate variant on {:?}", &path))?; + let file = settings + .dest + .join(cruet::to_snake_case(&variant_info.rust_module)) + .with_extension("rs"); + //TODO use a formatter like https://crates.io/crates/prettyplease? + fs::write(file, code)?; + variants.push(variant_info); + } + } + } + + let (module_name, code) = + generate_module(&hbs, &variants).with_context(|| "failed to generate module")?; + let file = settings.dest.join(module_name).with_extension("rs"); + //TODO use a formatter like https://crates.io/crates/prettyplease? + fs::write(file, code)?; + + Ok(()) +} + +fn generate_variant(hbs: &Handlebars, jsonschema: Value) -> Result<(VariantInfo, String)> { + // let id = jsonschema["$id"] + // .as_str() + // .ok_or(anyhow!("$id not found or not a string")) + // .and_then(|s| url::Url::parse(s).with_context(|| format!("failed to parse: {}", s)))?; + // let module_name = id + // .path_segments() + // .and_then(|v| v.last()) + // .map(cruet::to_snake_case) + // .ok_or(anyhow!("no path in $id"))? + // .replace("_event", ""); + + // extract module's name from `context.type` (and not from `$id`) + let context_type = jsonschema["properties"]["context"]["properties"]["type"]["default"] + .as_str() + .unwrap_or_default() + .to_string(); + + let fragments = context_type.split('.').collect::>(); + let rust_module = format!("{}_{}", fragments[2], fragments[3]).to_snake_case(); + let predicate = fragments[3].to_owned(); + // due to inconstency in case/format the subject could be not be extracted from the context.type (ty), jsonshema $id, spec filename (shema, examples) + let subject = jsonschema["properties"]["subject"]["properties"]["type"]["default"] + .as_str() + .unwrap_or_default() + .to_string(); + + let data = build_data_for_variants(jsonschema); + let code = hbs.render("variant", &data)?; + let variant_info = VariantInfo { + context_type, + rust_module, + subject, + predicate, + }; + Ok((variant_info, code)) +} + +fn generate_module(hbs: &Handlebars, variants: &[VariantInfo]) -> Result<(String, String)> { + let data = json!({ + "variants": variants + }); + let code = hbs.render("mod", &data)?; + Ok(("mod".to_string(), code)) +} + +fn build_data_for_variants(jsonschema: Value) -> Value { + let mut structs = vec![]; + let mut enums = vec![]; + collect_structs( + &mut structs, + &mut enums, + &["content"], + &jsonschema["properties"]["subject"]["properties"]["content"], + ); + structs.reverse(); + + json!({ + "structs": structs, + "enums": enums, + "jsonschema": jsonschema, + }) +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +struct TypeInfo { + type_declaration: String, + serde_with: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct VariantInfo { + context_type: String, + rust_module: String, + subject: String, + predicate: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct StructDef { + type_info: TypeInfo, + json_definition: Value, + fields: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct EnumDef { + type_info: TypeInfo, + json_definition: Value, + /// (is_default, value as string) + values: Vec<(bool, String)>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct FieldDef { + rust_name: String, + serde_name: String, + type_info: TypeInfo, + is_optional: bool, +} + +fn collect_structs( + structs: &mut Vec, + enums: &mut Vec, + field_names: &[&str], + json_definition: &Value, +) -> TypeInfo { + match json_definition["type"].as_str() { + Some("string") => match json_definition["format"].as_str() { + Some("date-time") => TypeInfo { + type_declaration: "time::OffsetDateTime".to_string(), + serde_with: Some("crate::serde::datetime".to_string()), + }, + //TODO manage purl + Some("uri-reference") => TypeInfo { + type_declaration: "crate::UriReference".to_string(), + serde_with: None, + }, + Some("uri") => TypeInfo { + type_declaration: "crate::Uri".to_string(), + serde_with: None, + }, + _ => match json_definition["enum"].as_array() { + None => { + let type_declaration = + match (field_names.last(), json_definition["minLength"].as_i64()) { + (Some(&"id"), _) => "crate::Id", + (Some(&"name"), Some(1)) => "crate::Name", + (Some(x), Some(1)) if x.ends_with("Id") => "crate::Id", + (Some(x), Some(1)) if x.ends_with("Name") => "crate::Name", + _ => "String", + } + .to_string(); + TypeInfo { + type_declaration, + ..Default::default() + } + } + Some(values) => { + let default_value = json_definition["default"].as_str(); + let values = values + .iter() + .map(|v| v.as_str().unwrap_or_default().to_string()) + .map(|v| (default_value == Some(&v), v)) + .collect::>(); + let type_info = TypeInfo { + type_declaration: to_type_name(field_names), + ..Default::default() + }; + enums.push(EnumDef { + type_info: type_info.clone(), + json_definition: json_definition.clone(), + values, + }); + type_info + } + }, + }, + Some("object") => match json_definition["properties"].as_object() { + None => TypeInfo { + type_declaration: "serde_json::Map".to_string(), + ..Default::default() + }, + Some(fields_kv) => { + let required = json_definition["required"].as_array(); + let fields = fields_kv + .into_iter() + .map(|field| { + let serde_name = field.0.to_string(); + let rust_name = if serde_name == "type" { + "ty".to_string() + } else { + serde_name.to_snake_case() + }; + let mut children_field_names = vec![]; + children_field_names.extend_from_slice(field_names); + children_field_names.push(&serde_name); + let mut type_info = + collect_structs(structs, enums, &children_field_names, field.1); + let field_name = json!(&serde_name); + let is_optional = + required.map(|a| !a.contains(&field_name)).unwrap_or(true); + if is_optional { + type_info.type_declaration = + format!("Option<{}>", type_info.type_declaration); + } + FieldDef { + rust_name, + serde_name, + type_info, + is_optional, + } + }) + .collect::>(); + let type_info = TypeInfo { + type_declaration: to_type_name(field_names), + ..Default::default() + }; + structs.push(StructDef { + type_info: type_info.clone(), + fields, + json_definition: json_definition.clone(), + }); + type_info + } + }, + Some(x) => todo!("impl for type='{}'", x), + None => unimplemented!("expected key 'type' in field '{}'", field_names.join(".")), + } +} + +fn to_type_name(fied_names: &[&str]) -> String { + fied_names.join("_").to_class_case() +} diff --git a/generator/templates/mod.hbs b/generator/templates/mod.hbs new file mode 100644 index 0000000..51f4665 --- /dev/null +++ b/generator/templates/mod.hbs @@ -0,0 +1,109 @@ +// @generated +// by cdevents/sdk-rust/generator (mod.hbs) + +use serde::de::Error; + +{{#each variants }} +pub mod {{this.rust_module}}; +{{/each}} + +use serde::{Serialize, Deserialize}; + +{{#each variants }} +pub const {{to_screaming_snake_case this.rust_module}}: &str = "{{ this.context_type }}"; +{{/each}} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(untagged)] // TODO how to use content of context.type as discriminator ? +pub enum Content { + {{#each variants }} + {{to_class_case this.rust_module}}({{this.rust_module}}::Content), + {{/each}} +} + +impl Content { + pub fn from_json(ty: &str, json: serde_json::Value) -> Result{ + match ty { + {{#each variants }} + {{to_screaming_snake_case this.rust_module}} => { + let variant: {{this.rust_module}}::Content = serde_json::from_value(json)?; + Ok(variant.into()) + }, + {{/each}} + variant => Err(serde_json::Error::custom(format_args!( + "unknown variant `{}`, expected 'dev.cdevents.\{{subject}}.\{{predicate}}.\{{version}}'", + variant, + ))), + } + } + + 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(&self) -> &'static str { + match self { + {{#each variants }} + Self::{{to_class_case this.rust_module}}(_) => "{{ this.subject }}", + {{/each}} + } + } + + pub fn predicate(&self) -> &'static str { + match self { + {{#each variants }} + Self::{{to_class_case this.rust_module}}(_) => "{{ this.predicate }}", + {{/each}} + } + } +} + +// due to inconstency in case/format the subject could be not be extracted from the context.type (ty), jsonshema $id, spec filename (shema, examples) +pub fn extract_subject_predicate(ty: &str) -> Option<(&str, &str)>{ + // let mut split = ty.split('.'); + match ty { + {{#each variants }} + {{to_screaming_snake_case this.rust_module}} => Some(("{{ this.subject }}", "{{ this.predicate }}")), + {{/each}} + _ => None, + } +} + +{{#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}} + +#[cfg(feature = "testkit")] +impl<> proptest::arbitrary::Arbitrary for Content { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::prelude::*; + prop_oneof![ +{{#each variants }} + any::<{{this.rust_module}}::Content>().prop_map(Content::from), +{{/each}} + ].boxed() + } +} + +// #[cfg(test)] +// mod tests { +// use super::*; +// +// #[test] +// fn test_true() { +// {{#each variants }} +// assert_eq!(extract_subject_predicate({{to_screaming_snake_case this.rust_module}}), Some(("{{ this.subject }}","{{ this.predicate }}"))); +// {{/each}} +// } +// } \ No newline at end of file diff --git a/generator/templates/variant.hbs b/generator/templates/variant.hbs new file mode 100644 index 0000000..8726957 --- /dev/null +++ b/generator/templates/variant.hbs @@ -0,0 +1,48 @@ +// @generated +// by cdevents/sdk-rust/generator (subject.hbs) + +#[cfg(feature = "testkit")] use proptest_derive::Arbitrary; +use serde::{Serialize, Deserialize}; +{{#each structs }} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +#[serde(deny_unknown_fields)] +pub struct {{ this.type_info.type_declaration }} { + {{#each this.fields }} + #[serde(rename = "{{ this.serde_name }}", + {{~#if this.is_optional }} default, skip_serializing_if = "Option::is_none",{{/if~}} + {{~#if this.type_info.serde_with }} with = "{{ this.type_info.serde_with }}{{#if this.is_optional }}_optional{{/if}}",{{/if~}} + )] + pub {{ this.rust_name }}: {{this.type_info.type_declaration }}, + {{/each}} +} +{{/each}} +{{#each enums }} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "testkit", derive(Arbitrary))] +pub enum {{ this.type_info.type_declaration }} { + {{#each this.values }} + #[serde(rename = "{{this.1}}")]{{#if this.0}} + #[default]{{/if}} + {{to_class_case this.1}}, + {{/each}} +} +{{/each}} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use super::*; + + proptest! { + #[test] + #[cfg(feature = "testkit")] + fn arbitraries_are_json_valid(s in any::()) { + let json_str = serde_json::to_string(&s).unwrap(); + let actual = serde_json::from_str::(&json_str).unwrap(); + assert_eq!(s, actual); + } + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..7897a24 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.75.0" diff --git a/tools/cargo-deny/deny.toml b/tools/cargo-deny/deny.toml index b6ceb5b..94f7eec 100644 --- a/tools/cargo-deny/deny.toml +++ b/tools/cargo-deny/deny.toml @@ -9,13 +9,14 @@ wildcards = "deny" unlicensed = "deny" copyleft = "deny" confidence-threshold = 0.95 -allow = [ - "Apache-2.0", - "MIT", - "BSD-2-Clause", -] +allow = ["Apache-2.0", "MIT", "BSD-2-Clause", "Unicode-DFS-2016"] exceptions = [] +# The unpublished packages (generator) would be ignored now +# FIXME the generator is excluded explicitly (see Makefile), I don't know why this is not working +[licenses.private] +ignore = true + [advisories] unmaintained = "deny" vulnerability = "deny" diff --git a/zz_artifact/Cargo.toml b/zz_artifact/Cargo.toml deleted file mode 100644 index b3154c8..0000000 --- a/zz_artifact/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_artifact" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_artifact/src/main.rs b/zz_artifact/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_artifact/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_branch/Cargo.toml b/zz_branch/Cargo.toml deleted file mode 100644 index 0ca65b3..0000000 --- a/zz_branch/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "zz_branch" -version = "0.1.0" -edition = "2021" -license = "MIT" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_branch/src/main.rs b/zz_branch/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_branch/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_build/Cargo.toml b/zz_build/Cargo.toml deleted file mode 100644 index a6e5725..0000000 --- a/zz_build/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_build" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_build/src/main.rs b/zz_build/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_build/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_change/Cargo.toml b/zz_change/Cargo.toml deleted file mode 100644 index 2c12cc1..0000000 --- a/zz_change/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_change" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_change/src/main.rs b/zz_change/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_change/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_environment/Cargo.toml b/zz_environment/Cargo.toml deleted file mode 100644 index 74aca6d..0000000 --- a/zz_environment/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_environment" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_environment/src/main.rs b/zz_environment/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_environment/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_incident/Cargo.toml b/zz_incident/Cargo.toml deleted file mode 100644 index 219775c..0000000 --- a/zz_incident/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_incident" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_incident/src/main.rs b/zz_incident/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_incident/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_pipeline/Cargo.toml b/zz_pipeline/Cargo.toml deleted file mode 100644 index d6d8b3f..0000000 --- a/zz_pipeline/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_pipeline" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_pipeline/src/main.rs b/zz_pipeline/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_pipeline/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_repository/Cargo.toml b/zz_repository/Cargo.toml deleted file mode 100644 index 5ba7ef0..0000000 --- a/zz_repository/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_repository" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_repository/src/main.rs b/zz_repository/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_repository/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_service/Cargo.toml b/zz_service/Cargo.toml deleted file mode 100644 index a52932e..0000000 --- a/zz_service/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_service" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_service/src/main.rs b/zz_service/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_service/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/zz_task/Cargo.toml b/zz_task/Cargo.toml deleted file mode 100644 index 428d7bb..0000000 --- a/zz_task/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "zz_task" -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/zz_task/src/main.rs b/zz_task/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/zz_task/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -}