feat: add actions sdk
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
02dd805db4
commit
186f13a16c
33
Cargo.lock
generated
33
Cargo.lock
generated
@ -183,6 +183,23 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cuddle-actions"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"clap",
|
||||||
|
"pretty_assertions",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenv"
|
name = "dotenv"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
@ -373,6 +390,16 @@ version = "0.2.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
@ -783,3 +810,9 @@ checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
@ -14,3 +14,6 @@ tracing = { version = "0.1", features = ["log"] }
|
|||||||
tracing-subscriber = { version = "0.3.18" }
|
tracing-subscriber = { version = "0.3.18" }
|
||||||
clap = { version = "4", features = ["derive", "env"] }
|
clap = { version = "4", features = ["derive", "env"] }
|
||||||
dotenv = { version = "0.15" }
|
dotenv = { version = "0.15" }
|
||||||
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
|
serde_json = "1.0.127"
|
||||||
|
uuid = { version = "1.7.0", features = ["v4"] }
|
||||||
|
13
crates/cuddle-actions/Cargo.toml
Normal file
13
crates/cuddle-actions/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "cuddle-actions"
|
||||||
|
edition = "2021"
|
||||||
|
version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow.workspace = true
|
||||||
|
clap.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = "1.4.0"
|
93
crates/cuddle-actions/src/lib.rs
Normal file
93
crates/cuddle-actions/src/lib.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Cuddle actions is a two part action, it is called from cuddle itself, second the cli uses a provided sdk to expose functionality
|
||||||
|
|
||||||
|
use std::{collections::BTreeMap, ffi::OsString, io::Write};
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
// Fix design make it so that it works like axum!
|
||||||
|
|
||||||
|
type ActionFn = dyn Fn() + 'static;
|
||||||
|
|
||||||
|
struct Action {
|
||||||
|
name: String,
|
||||||
|
description: Option<String>,
|
||||||
|
f: Box<ActionFn>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
struct ActionSchema<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
description: Option<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CuddleActions {
|
||||||
|
actions: BTreeMap<String, Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct AddActionOptions {
|
||||||
|
description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CuddleActions {
|
||||||
|
pub fn add_action<F>(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
action_fn: F,
|
||||||
|
options: &AddActionOptions,
|
||||||
|
) -> &mut Self
|
||||||
|
where
|
||||||
|
F: Fn() + 'static,
|
||||||
|
{
|
||||||
|
self.actions.insert(
|
||||||
|
name.into(),
|
||||||
|
Action {
|
||||||
|
name: name.into(),
|
||||||
|
description: options.description.clone(),
|
||||||
|
f: Box::new(action_fn),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&mut self) -> anyhow::Result<()> {
|
||||||
|
let output = self.execute_from(std::env::args())?;
|
||||||
|
|
||||||
|
// Write all stdout to buffer
|
||||||
|
std::io::stdout().write_all(output.as_bytes())?;
|
||||||
|
std::io::stdout().write_all("\n".as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_from<I, T>(&mut self, items: I) -> anyhow::Result<String>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
T: Into<OsString> + Clone,
|
||||||
|
{
|
||||||
|
let root = clap::Command::new("cuddle-action")
|
||||||
|
.subcommand_required(true)
|
||||||
|
.subcommand(clap::Command::new("schema"));
|
||||||
|
|
||||||
|
let matches = root.get_matches_from(items);
|
||||||
|
match matches.subcommand().expect("subcommand to be required") {
|
||||||
|
("schema", _args) => {
|
||||||
|
let schema = self
|
||||||
|
.actions
|
||||||
|
.values()
|
||||||
|
.map(|a| ActionSchema {
|
||||||
|
name: &a.name,
|
||||||
|
description: a.description.as_ref().map(|d| d.as_str()),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let output = serde_json::to_string_pretty(&schema)?;
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
_ => Ok("".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
crates/cuddle-actions/tests/mod.rs
Normal file
31
crates/cuddle-actions/tests/mod.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use cuddle_actions::AddActionOptions;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_schema_no_actions() -> anyhow::Result<()> {
|
||||||
|
let output =
|
||||||
|
cuddle_actions::CuddleActions::default().execute_from(vec!["cuddle-actions", "schema"])?;
|
||||||
|
|
||||||
|
assert_eq!("[]", &output);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_schema_simple_action() -> anyhow::Result<()> {
|
||||||
|
let output = cuddle_actions::CuddleActions::default()
|
||||||
|
.add_action("something", || {}, &AddActionOptions::default())
|
||||||
|
.execute_from(vec!["cuddle-actions", "schema"])?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
r#"[
|
||||||
|
{
|
||||||
|
"name": "something",
|
||||||
|
"description": null
|
||||||
|
}
|
||||||
|
]"#,
|
||||||
|
&output
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -11,9 +11,9 @@ tracing.workspace = true
|
|||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
dotenv.workspace = true
|
dotenv.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
uuid.workspace = true
|
||||||
|
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
|
||||||
uuid = { version = "1.7.0", features = ["v4"] }
|
|
||||||
toml = "0.8.19"
|
toml = "0.8.19"
|
||||||
fs_extra = "1.3.0"
|
fs_extra = "1.3.0"
|
||||||
serde_json = "1.0.127"
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
{"ProjectSchema":{"fields":{"name":{"fields":null,"type":null,"contracts":["String"],"documentation":null}},"type":null,"contracts":[],"documentation":null}}
|
Loading…
Reference in New Issue
Block a user