diff --git a/Cargo.lock b/Cargo.lock index 80e8982203..07a03b0a8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -925,6 +925,7 @@ dependencies = [ "clap", "comfy-table", "current_platform", + "enum-display", "fluvio", "fluvio-cli-common", "fluvio-connector-deployer", @@ -1990,18 +1991,18 @@ dependencies = [ [[package]] name = "enum-display" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d4df33d54dd1959d177a0e2c2f4e5a8637a3054aa56861ed7e173ad2043fe2" +checksum = "02058bb25d8d0605829af88230427dd5cd50661590bd2b09d1baf7c64c417f24" dependencies = [ "enum-display-macro", ] [[package]] name = "enum-display-macro" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ce3a36047ede676eb0d2721d065beed8410cf4f113f489604d2971331cb378" +checksum = "d4be2cf2fe7b971b1865febbacd4d8df544aa6bd377cca011a6d69dcf4c60d94" dependencies = [ "convert_case", "quote", diff --git a/Cargo.toml b/Cargo.toml index 71e7161b74..45f6c7b475 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ dialoguer = "0.11.0" directories = "5.0.0" dirs = "5.0.0" duct = { version = "0.13", default-features = false } +enum-display = "0.1.3" event-listener = "3.1.0" eyre = { version = "0.6", default-features = false } flate2 = { version = "1.0.25" } diff --git a/connector/cargo_template/Cargo.toml.liquid b/connector/cargo_template/Cargo.toml.liquid index bce6a26283..1a2be434e1 100644 --- a/connector/cargo_template/Cargo.toml.liquid +++ b/connector/cargo_template/Cargo.toml.liquid @@ -4,6 +4,8 @@ version = "0.1.0" authors = ["{{authors}}"] edition = "2021" +[workspace] + [dependencies] {% if connector-type == "sink" %}futures = { version = "0.3", default-features = false }{% endif %} serde = { version = "1.0", default-features = false, features = ["derive"]} diff --git a/crates/cdk/Cargo.toml b/crates/cdk/Cargo.toml index e7f48ad2f3..7bf859f45e 100644 --- a/crates/cdk/Cargo.toml +++ b/crates/cdk/Cargo.toml @@ -23,6 +23,7 @@ cargo-generate = { workspace = true } clap = { workspace = true, features = ["std", "derive", "help", "usage", "error-context", "env", "wrap_help", "suggestions"], default-features = false } comfy-table = { workspace = true } current_platform = { workspace = true } +enum-display = { workspace = true } include_dir = { workspace = true } serde = { workspace = true, features = ["derive"] } sysinfo = { workspace = true, default-features = false } diff --git a/crates/cdk/src/generate.rs b/crates/cdk/src/generate.rs index bfaf05c870..6866790ec0 100644 --- a/crates/cdk/src/generate.rs +++ b/crates/cdk/src/generate.rs @@ -1,11 +1,14 @@ -use std::{fmt::Debug, path::PathBuf}; +use std::fmt::Debug; +use std::fmt::Display; +use std::path::PathBuf; use anyhow::{Result, Error}; -use clap::Parser; +use clap::{Parser, ValueEnum}; use cargo_generate::{GenerateArgs, TemplatePath, generate}; use include_dir::{Dir, include_dir}; use tempfile::TempDir; +use enum_display::EnumDisplay; // Note: Cargo.toml.liquid files are changed by cargo-generate to Cargo.toml // this avoids the problem of cargo trying to parse Cargo.toml template files @@ -17,9 +20,17 @@ static CONNECTOR_TEMPLATE: Dir<'static> = /// Generate new SmartConnector project #[derive(Debug, Parser)] pub struct GenerateCmd { - /// SmartConnector Project Name + /// Connector Name name: Option, + #[arg(long, value_name = "GROUP")] + /// Connector developer group + group: Option, + + /// Connector description used as part of the project metadata + #[arg(long, value_name = "DESCRIPTION")] + conn_description: Option, + /// Local path to generate the SmartConnector project. /// Default to directory with project name, created in current directory #[arg(long, env = "CDK_DESTINATION", value_name = "PATH")] @@ -28,6 +39,16 @@ pub struct GenerateCmd { /// Disable interactive prompt. Take all values from CLI flags. Fail if a value is missing. #[arg(long, hide_short_help = true)] silent: bool, + + /// Type of Connector project to generate. + /// Skip prompt if value given. + #[arg(long, value_enum, value_name = "TYPE", env = "CDK_CONN_TYPE")] + conn_type: Option, + + /// Visibility of Connector project to generate. + /// Skip prompt if value given. + #[arg(long, value_enum, value_name = "PUBLIC", env = "CDK_CONN_PUBLIC")] + conn_public: Option, } impl GenerateCmd { @@ -46,8 +67,14 @@ impl GenerateCmd { ..Default::default() }; - let fluvio_dependency_version_hash = - format!("fluvio-cargo-dependency-hash={}", env!("GIT_HASH")); + let mut maybe_user_input = CdkTemplateUserValues::new(); + + maybe_user_input + .with_name(self.name.clone()) + .with_group(self.group) + .with_description(self.conn_description) + .with_conn_type(self.conn_type) + .with_conn_public(self.conn_public); let args = GenerateArgs { name: self.name, @@ -55,7 +82,7 @@ impl GenerateCmd { verbose: !self.silent, silent: self.silent, destination: self.destination, - define: vec![fluvio_dependency_version_hash], + define: maybe_user_input.to_cargo_generate(), ..Default::default() }; @@ -64,3 +91,110 @@ impl GenerateCmd { Ok(()) } } + +#[derive(ValueEnum, Clone, Debug, Parser, PartialEq, Eq, EnumDisplay)] +#[clap(rename_all = "kebab-case")] +#[enum_display(case = "Kebab")] +enum ConnectorType { + Sink, + Source, +} + +#[derive(Clone, Debug)] +enum CdkTemplateValue { + Name(String), + Group(String), + Description(String), + ConnFluvioDependencyHash(String), + ConnType(ConnectorType), + ConnPublic(bool), +} + +impl Display for CdkTemplateValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CdkTemplateValue::Name(name) => write!(f, "project-name={}", name), + CdkTemplateValue::Group(group) => write!(f, "project-group={}", group), + CdkTemplateValue::Description(description) => { + write!(f, "project-description={}", description) + } + CdkTemplateValue::ConnFluvioDependencyHash(hash) => { + write!(f, "fluvio-cargo-dependency-hash={}", hash) + } + CdkTemplateValue::ConnType(conn_type) => write!(f, "connector-type={conn_type}"), + CdkTemplateValue::ConnPublic(conn_public) => { + write!(f, "connector-public={conn_public}") + } + } + } +} + +#[derive(Debug, Default, Clone)] +struct CdkTemplateUserValues { + values: Vec, +} + +impl CdkTemplateUserValues { + fn new() -> Self { + // By default the fluvio dependency hash is the current git hash + // and its always passed as option to cargo generate + let values = vec![CdkTemplateValue::ConnFluvioDependencyHash( + env!("GIT_HASH").to_string(), + )]; + + Self { values } + } + + fn to_vec(&self) -> Vec { + self.values.clone() + } + + fn to_cargo_generate(&self) -> Vec { + self.to_vec().iter().map(|v| v.to_string()).collect() + } + + fn with_name(&mut self, value: Option) -> &mut Self { + if let Some(v) = value { + tracing::debug!("CDK Argument - project-name={}", v); + self.values.push(CdkTemplateValue::Name(v)); + } + + self + } + + fn with_group(&mut self, value: Option) -> &mut Self { + if let Some(v) = value { + tracing::debug!("CDK Argument - project-group={}", v); + self.values.push(CdkTemplateValue::Group(v)); + } + + self + } + + fn with_description(&mut self, value: Option) -> &mut Self { + if let Some(v) = value { + tracing::debug!("CDK Argument - project-description={}", v); + self.values.push(CdkTemplateValue::Description(v)); + } + + self + } + + fn with_conn_type(&mut self, value: Option) -> &mut Self { + if let Some(v) = value { + tracing::debug!("CDK Argument - connector-type={}", v); + self.values.push(CdkTemplateValue::ConnType(v)); + } + + self + } + + fn with_conn_public(&mut self, value: Option) -> &mut Self { + if let Some(v) = value { + tracing::debug!("CDK Argument - connector-public={}", v); + self.values.push(CdkTemplateValue::ConnPublic(v)); + } + + self + } +} diff --git a/crates/smartmodule-development-kit/Cargo.toml b/crates/smartmodule-development-kit/Cargo.toml index 0fc25259f7..debf2c57c0 100644 --- a/crates/smartmodule-development-kit/Cargo.toml +++ b/crates/smartmodule-development-kit/Cargo.toml @@ -19,12 +19,12 @@ anyhow = { workspace = true } clap = { workspace = true, features = ["std", "derive", "help", "usage", "error-context", "env", "wrap_help", "suggestions"], default-features = false } current_platform = { workspace = true } dirs = { workspace = true } +enum-display = { workspace = true } toml = { workspace = true } tokio = { workspace = true } cargo-generate = { workspace = true } include_dir = { workspace = true } tempfile = { workspace = true } -enum-display = "0.1.3" lib-cargo-crate = "0.2.1" diff --git a/tests/cli/cdk_smoke_tests/cdk-basic.bats b/tests/cli/cdk_smoke_tests/cdk-basic.bats index 300a608d7f..aadcea23fc 100644 --- a/tests/cli/cdk_smoke_tests/cdk-basic.bats +++ b/tests/cli/cdk_smoke_tests/cdk-basic.bats @@ -170,6 +170,65 @@ setup_file() { assert_success } +@test "Generate and Builds a Sink Connector Package" { + export SINK_CONN_NAME="$PROJECT_NAME_PREFIX-my-sink-conn" + + # move into test dir + cd $TEST_DIR + + # generate a sink connector + run $CDK_BIN generate $SINK_CONN_NAME \ + --group "$PROJECT_NAME_PREFIX" \ + --conn-description "My Sink Connector" \ + --conn-type sink \ + --conn-public true + assert_success + + # cd into the sink connector directory + cd $SINK_CONN_NAME + + # build connector + run $CDK_BIN build --target x86_64-unknown-linux-gnu + assert_success +} + +@test "Generate and Builds a Source Connector Package" { + export SOURCE_CONN_NAME="$PROJECT_NAME_PREFIX-my-source-conn" + + # move into test dir + cd $TEST_DIR + + # generate a source connector + run $CDK_BIN generate $SOURCE_CONN_NAME \ + --group "$PROJECT_NAME_PREFIX" \ + --conn-description "My Source Connector" \ + --conn-type source \ + --conn-public true + assert_success + + # cd into the source connector directory + cd $SOURCE_CONN_NAME + + # build connector + run $CDK_BIN build --target x86_64-unknown-linux-gnu + assert_success +} + +@test "Fails on unsupported/invalid connector type" { + export BAD_TYPE_CONN_NAME="$PROJECT_NAME_PREFIX-my-bad-type-conn" + + # move into test dir + cd $TEST_DIR + + # generate a sink connector + run $CDK_BIN generate $BAD_TYPE_CONN_NAME \ + --group "$PROJECT_NAME_PREFIX" \ + --conn-description "My Source Connector" \ + --conn-type bad-type \ + --conn-public true + assert_failure +} + # fix CI authentication to hub service first: # https://github.com/infinyon/fluvio/issues/3634 # @test "List connectors from hub" {