From 608ed32eacbe413340d0e1d693a3eaeb6e37144e Mon Sep 17 00:00:00 2001 From: thibaud-leclere Date: Tue, 14 Apr 2026 10:41:17 +0200 Subject: [PATCH] ci: add quality workflow and notifier test coverage --- .github/workflows/quality.yml | 53 +++++++++++ package.json | 7 +- src-tauri/src/services/notifier.rs | 146 +++++++++++++++++++++++++---- 3 files changed, 188 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/quality.yml diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000..4faa571 --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,53 @@ +name: Quality + +on: + push: + branches: ["main"] + pull_request: + +jobs: + quality: + runs-on: ubuntu-24.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Linux system deps for Tauri + run: | + sudo apt-get update + sudo apt-get install -y \ + pkg-config \ + libwebkit2gtk-4.1-dev \ + libsoup-3.0-dev \ + libjavascriptcoregtk-4.1-dev + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install JS deps + run: npm ci + + - name: Check system deps script + run: npm run deps:check + + - name: Frontend typecheck + run: npx tsc --noEmit + + - name: Rust check + working-directory: src-tauri + run: cargo check + + - name: Rust tests + working-directory: src-tauri + run: cargo test + + - name: Rust clippy + working-directory: src-tauri + run: cargo clippy -- -D warnings diff --git a/package.json b/package.json index 0e9561f..ca9fe41 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,12 @@ "preview": "vite preview", "tauri": "tauri", "deps:check": "bash scripts/tauri-system-deps.sh check", - "deps:install": "bash scripts/tauri-system-deps.sh install" + "deps:install": "bash scripts/tauri-system-deps.sh install", + "qa:frontend": "npx tsc --noEmit", + "qa:backend:check": "cd src-tauri && cargo check", + "qa:backend:test": "cd src-tauri && cargo test", + "qa:backend:clippy": "cd src-tauri && cargo clippy -- -D warnings", + "qa": "npm run qa:frontend && npm run qa:backend:check && npm run qa:backend:test && npm run qa:backend:clippy" }, "dependencies": { "@tauri-apps/api": "^2.10.1", diff --git a/src-tauri/src/services/notifier.rs b/src-tauri/src/services/notifier.rs index caae74a..fab2f8b 100644 --- a/src-tauri/src/services/notifier.rs +++ b/src-tauri/src/services/notifier.rs @@ -3,6 +3,26 @@ use rusqlite::Connection; use std::sync::{Arc, Mutex}; use tauri::{AppHandle, Emitter}; +pub fn create( + db: &Arc>, + project_id: &str, + ticket_id: Option<&str>, + notification_type: &str, + title: &str, + message: &str, +) -> Result { + let conn = db.lock().map_err(|e| format!("DB lock failed: {}", e))?; + Notification::insert( + &conn, + project_id, + ticket_id, + notification_type, + title, + message, + ) + .map_err(|e| format!("Failed to insert notification: {}", e)) +} + pub fn create_and_emit( db: &Arc>, app_handle: &AppHandle, @@ -12,18 +32,7 @@ pub fn create_and_emit( title: &str, message: &str, ) -> Result { - let notification = { - let conn = db.lock().map_err(|e| format!("DB lock failed: {}", e))?; - Notification::insert( - &conn, - project_id, - ticket_id, - notification_type, - title, - message, - ) - .map_err(|e| format!("Failed to insert notification: {}", e))? - }; + let notification = create(db, project_id, ticket_id, notification_type, title, message)?; let _ = app_handle.emit( "new-notification", @@ -35,6 +44,14 @@ pub fn create_and_emit( Ok(notification) } +fn error_message(error: &str) -> String { + if error.is_empty() { + "Erreur lors du traitement du ticket".to_string() + } else { + error.to_string() + } +} + pub fn notify_new_ticket( db: &Arc>, app_handle: &AppHandle, @@ -105,11 +122,7 @@ pub fn notify_error( error: &str, ) { let title = format!("Erreur ticket #{}", artifact_id); - let message = if error.is_empty() { - "Erreur lors du traitement du ticket".to_string() - } else { - error.to_string() - }; + let message = error_message(error); let _ = create_and_emit( db, @@ -121,3 +134,102 @@ pub fn notify_error( &message, ); } + +#[cfg(test)] +mod tests { + use super::*; + use crate::db; + use crate::models::project::Project; + use crate::models::ticket::ProcessedTicket; + use crate::models::tracker::{AgentConfig, WatchedTracker}; + + fn setup() -> (Arc>, String) { + let conn = db::init_in_memory().expect("db init should succeed"); + let project = Project::insert(&conn, "Notif Project", "/tmp/notif", None, "main") + .expect("project insert should succeed"); + (Arc::new(Mutex::new(conn)), project.id) + } + + fn setup_ticket(db: &Arc>, project_id: &str) -> String { + let conn = db.lock().expect("db lock should succeed"); + + let tracker = WatchedTracker::insert( + &conn, + project_id, + 101, + "Bugs", + 10, + AgentConfig { + analyst_command: "echo".to_string(), + analyst_args: vec![], + developer_command: "echo".to_string(), + developer_args: vec![], + }, + vec![], + ) + .expect("tracker insert should succeed"); + + let ticket = ProcessedTicket::insert_if_new( + &conn, + &tracker.id, + 1, + "Ticket 1", + "{\"id\":1}", + ) + .expect("ticket insert should succeed") + .expect("ticket should be inserted"); + + ticket.id + } + + #[test] + fn test_create_notification() { + let (db, project_id) = setup(); + + let n = create( + &db, + &project_id, + None, + "NewTicket", + "Ticket #12", + "Nouveau ticket detecte", + ) + .expect("notification should be inserted"); + + assert_eq!(n.project_id, project_id); + assert_eq!(n.ticket_id, None); + assert_eq!(n.notification_type, "NewTicket"); + assert_eq!(n.title, "Ticket #12"); + assert_eq!(n.message, "Nouveau ticket detecte"); + assert!(!n.read); + } + + #[test] + fn test_create_notification_with_ticket() { + let (db, project_id) = setup(); + let ticket_id = setup_ticket(&db, &project_id); + + let n = create( + &db, + &project_id, + Some(&ticket_id), + "FixReady", + "Fix pret #1", + "Un correctif est disponible pour revue", + ) + .expect("notification should be inserted"); + + assert_eq!(n.ticket_id.as_deref(), Some(ticket_id.as_str())); + assert_eq!(n.notification_type, "FixReady"); + } + + #[test] + fn test_error_message_default_when_empty() { + assert_eq!(error_message(""), "Erreur lors du traitement du ticket"); + } + + #[test] + fn test_error_message_keeps_original() { + assert_eq!(error_message("timeout"), "timeout"); + } +}