ci: add quality workflow and notifier test coverage

This commit is contained in:
thibaud-leclere 2026-04-14 10:41:17 +02:00
parent 6912e51b14
commit 608ed32eac
3 changed files with 188 additions and 18 deletions

53
.github/workflows/quality.yml vendored Normal file
View file

@ -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

View file

@ -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",

View file

@ -3,6 +3,26 @@ use rusqlite::Connection;
use std::sync::{Arc, Mutex};
use tauri::{AppHandle, Emitter};
pub fn create(
db: &Arc<Mutex<Connection>>,
project_id: &str,
ticket_id: Option<&str>,
notification_type: &str,
title: &str,
message: &str,
) -> Result<Notification, String> {
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<Mutex<Connection>>,
app_handle: &AppHandle,
@ -12,18 +32,7 @@ pub fn create_and_emit(
title: &str,
message: &str,
) -> Result<Notification, String> {
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<Mutex<Connection>>,
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<Mutex<Connection>>, 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<Mutex<Connection>>, 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");
}
}