diff --git a/src/bin/syzctl.rs b/src/bin/syzctl.rs index a1a47b9..881d698 100644 --- a/src/bin/syzctl.rs +++ b/src/bin/syzctl.rs @@ -1,4 +1,4 @@ -use clap::Parser; +use clap::{Parser, Subcommand}; use syz::tui::{run, Options}; #[derive(Parser, Debug)] @@ -11,17 +11,58 @@ struct Args { /// Auth token #[arg(short, long, env = "SYZD_AUTH_TOKEN")] token: String, + + #[command(subcommand)] + command: Option, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// Add a new project in the format platform:repository + Add { + /// The project to add (e.g., github:owner/repo) + argument: String, + }, } #[tokio::main] async fn main() -> anyhow::Result<()> { let args = Args::parse(); - run(Options { - url: args.url, - token: args.token, - }) - .await?; + match args.command { + Some(Commands::Add { argument }) => { + let parts: Vec<&str> = argument.split(':').collect(); + if parts.len() != 2 { + anyhow::bail!("Invalid argument format. Expected platform:repository"); + } + + let platform = parts[0].to_string(); + let repository = parts[1].to_string(); + + let client = reqwest::Client::new(); + let payload = serde_json::json!({ + "type": "AddProject", + "platform": platform, + "repository": repository, + }); + + client + .post(format!("{}/messages", args.url)) + .header("Authorization", format!("Bearer {}", args.token)) + .json(&payload) + .send() + .await?; + + println!("Project added successfully (command sent)."); + } + None => { + run(Options { + url: args.url, + token: args.token, + }) + .await?; + } + } Ok(()) } diff --git a/src/core/message.rs b/src/core/message.rs index 89534c8..212947d 100644 --- a/src/core/message.rs +++ b/src/core/message.rs @@ -29,6 +29,12 @@ pub enum Payload { project_id: String, }, + /// Add a new project to the database. + AddProject { + platform: String, + repository: String, + }, + /// Approve a Bump to be processed. This only updates the database but does not /// schedule the actual update task. ApproveBump { @@ -139,6 +145,19 @@ impl Payload { super::actions::analyze_project_dependencies::run(app, project_id).await } + Payload::AddProject { platform, repository } => { + let project = app.store().add_project(platform, repository).await?; + + app.handle().broadcast(crate::core::event::Event::Commit { + ops: vec![crate::core::event::Op::Upsert { + path: format!("project/{}", project.id), + data: serde_json::to_value(project).unwrap_or_default(), + }], + })?; + + Ok(()) + } + Payload::ApproveBump { bump_id } => { let updated_bump = app.store().approve_bump(&bump_id).await?; diff --git a/src/core/store.rs b/src/core/store.rs index a777f66..2ebd9a5 100644 --- a/src/core/store.rs +++ b/src/core/store.rs @@ -63,6 +63,24 @@ impl Store { Err(anyhow::anyhow!("Project not found")) } + pub async fn add_project(&self, platform: String, repository: String) -> Result { + let conn = self.database.conn()?; + let id = pk(); + + conn.execute( + "INSERT INTO project (id, platform, repository) VALUES (?, ?, ?)", + params![id.as_str(), platform.as_str(), repository.as_str()], + ) + .await + .context("Failed to insert project")?; + + Ok(Project { + id, + platform, + repository, + }) + } + pub async fn list_dependencies(&self) -> Result> { let conn = self.database.conn()?;