From 88c75e43aeb527b4d8a34f7e97df1d12d4c26b57 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Wed, 8 Apr 2026 06:56:09 +0100 Subject: [PATCH] update jenkinsfile --- Makefile | 17 +++++- crates/console/prometeu-drivers/src/audio.rs | 6 +- crates/console/prometeu-drivers/src/gfx.rs | 15 ++--- crates/console/prometeu-hal/src/cartridge.rs | 13 ++-- .../prometeu-system/src/services/memcard.rs | 32 ++++++---- .../src/virtual_machine_runtime/dispatch.rs | 6 +- files/config/Jenkinsfile | 61 +++++++++++++++---- 7 files changed, 103 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index f50d0f8d..26581673 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: fmt fmt-check clippy test test-debugger-socket ci +.PHONY: fmt fmt-check clippy tes-local test-debugger-socket test ci cobertura fmt: cargo fmt @@ -9,10 +9,21 @@ fmt-check: clippy: cargo clippy --workspace --all-features -test: +test-local: cargo test --workspace --all-targets --all-features --no-fail-fast test-debugger-socket: cargo test -p prometeu-host-desktop-winit --lib -- --ignored -ci: fmt-check clippy test +coverage: + cargo llvm-cov --workspace --all-features --html --output-dir target/llvm-cov/html --fail-under-lines 20 --fail-under-functions 20 --fail-under-regions 20 + +coverage-xml: + cargo llvm-cov report --workspace --all-features --cobertura --output-path target/llvm-cov/cobertura.xml + +coverage-json: + cargo llvm-cov report --workspace --all-features --json --summary-only --output-path target/llvm-cov/summary.json + +test: fmt-check clippy test-local test-debugger-socket +ci: fmt-check clippy coverage +cobertura: coverage-xml coverage-json diff --git a/crates/console/prometeu-drivers/src/audio.rs b/crates/console/prometeu-drivers/src/audio.rs index cdace8e6..3e578712 100644 --- a/crates/console/prometeu-drivers/src/audio.rs +++ b/crates/console/prometeu-drivers/src/audio.rs @@ -188,7 +188,8 @@ impl Audio { return AudioOpStatus::BankInvalid; } - let sample = bank_slot.and_then(|bank| bank.samples.get(sample_id as usize).map(Arc::clone)); + let sample = + bank_slot.and_then(|bank| bank.samples.get(sample_id as usize).map(Arc::clone)); if let Some(s) = sample { // println!( @@ -322,8 +323,7 @@ mod tests { let sound_banks = Arc::clone(&banks) as Arc; let mut audio = Audio::new(sound_banks); - let status = - audio.play_sample(sample(), MAX_CHANNELS, 255, 128, 1.0, 0, LoopMode::Off); + let status = audio.play_sample(sample(), MAX_CHANNELS, 255, 128, 1.0, 0, LoopMode::Off); assert_eq!(status, AudioOpStatus::VoiceInvalid); assert!(!audio.voices.iter().any(|voice| voice.active)); diff --git a/crates/console/prometeu-drivers/src/gfx.rs b/crates/console/prometeu-drivers/src/gfx.rs index 2af12a06..3c98bdea 100644 --- a/crates/console/prometeu-drivers/src/gfx.rs +++ b/crates/console/prometeu-drivers/src/gfx.rs @@ -872,16 +872,13 @@ impl Gfx { let glyph = glyph_for_char(c); let raw = color.0; - let row_start = (-y).max(0).min(5) as usize; - let row_end = (screen_h - y).max(0).min(5) as usize; - let col_start = (-x).max(0).min(3) as usize; - let col_end = (screen_w - x).max(0).min(3) as usize; + let row_start = (-y).clamp(0, 5) as usize; + let row_end = (screen_h - y).clamp(0, 5) as usize; + let col_start = (-x).clamp(0, 3) as usize; + let col_end = (screen_w - x).clamp(0, 3) as usize; - for (row_idx, row) in glyph - .iter() - .enumerate() - .skip(row_start) - .take(row_end.saturating_sub(row_start)) + for (row_idx, row) in + glyph.iter().enumerate().skip(row_start).take(row_end.saturating_sub(row_start)) { let py = (y + row_idx as i32) as usize; let base = py * self.w; diff --git a/crates/console/prometeu-hal/src/cartridge.rs b/crates/console/prometeu-hal/src/cartridge.rs index c61ae695..eb49f03c 100644 --- a/crates/console/prometeu-hal/src/cartridge.rs +++ b/crates/console/prometeu-hal/src/cartridge.rs @@ -87,9 +87,12 @@ impl AssetsPayloadSource { pub fn open_slice(&self, offset: u64, size: u64) -> io::Result { match self { Self::Memory(bytes) => { - let start = usize::try_from(offset).map_err(|_| invalid_input("asset offset overflow"))?; - let len = usize::try_from(size).map_err(|_| invalid_input("asset size overflow"))?; - let end = start.checked_add(len).ok_or_else(|| invalid_input("asset range overflow"))?; + let start = + usize::try_from(offset).map_err(|_| invalid_input("asset offset overflow"))?; + let len = + usize::try_from(size).map_err(|_| invalid_input("asset size overflow"))?; + let end = + start.checked_add(len).ok_or_else(|| invalid_input("asset range overflow"))?; if end > bytes.len() { return Err(invalid_input("asset range out of bounds")); } @@ -97,7 +100,9 @@ impl AssetsPayloadSource { Ok(AssetsPayloadSlice::Memory { bytes: Arc::clone(bytes), start, len }) } Self::File(source) => { - let end = offset.checked_add(size).ok_or_else(|| invalid_input("asset range overflow"))?; + let end = offset + .checked_add(size) + .ok_or_else(|| invalid_input("asset range overflow"))?; if end > source.payload_len { return Err(invalid_input("asset range out of bounds")); } diff --git a/crates/console/prometeu-system/src/services/memcard.rs b/crates/console/prometeu-system/src/services/memcard.rs index 661dba87..a53b5436 100644 --- a/crates/console/prometeu-system/src/services/memcard.rs +++ b/crates/console/prometeu-system/src/services/memcard.rs @@ -132,11 +132,9 @@ impl MemcardService { match self.load_committed(fs, app_id, slot) { Ok(Some(committed)) => Self::slice_payload(&committed.payload, offset, max_bytes), - Ok(None) => MemcardReadResult { - status: MemcardStatus::Empty, - bytes: Vec::new(), - bytes_read: 0, - }, + Ok(None) => { + MemcardReadResult { status: MemcardStatus::Empty, bytes: Vec::new(), bytes_read: 0 } + } Err(status) => MemcardReadResult { status, bytes: Vec::new(), bytes_read: 0 }, } } @@ -224,7 +222,11 @@ impl MemcardService { fn slice_payload(payload: &[u8], offset: usize, max_bytes: usize) -> MemcardReadResult { if offset >= payload.len() || max_bytes == 0 { - return MemcardReadResult { status: MemcardStatus::Ok, bytes: Vec::new(), bytes_read: 0 }; + return MemcardReadResult { + status: MemcardStatus::Ok, + bytes: Vec::new(), + bytes_read: 0, + }; } let end = payload.len().min(offset.saturating_add(max_bytes)); let bytes = payload[offset..end].to_vec(); @@ -276,11 +278,13 @@ fn make_save_uuid(app_id: u32, slot: u8) -> [u8; 16] { let mut out = [0u8; 16]; out[0..4].copy_from_slice(&app_id.to_le_bytes()); out[4] = slot; - out[5..13].copy_from_slice(&(std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .map(|d| d.as_nanos() as u64) - .unwrap_or(0)) - .to_le_bytes()); + out[5..13].copy_from_slice( + &(std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_nanos() as u64) + .unwrap_or(0)) + .to_le_bytes(), + ); out[13] = 0x50; out[14] = 0x4D; out[15] = 0x31; @@ -312,8 +316,10 @@ fn decode_slot_file(bytes: &[u8]) -> Result { let mut save_uuid = [0u8; 16]; save_uuid.copy_from_slice(&bytes[5..21]); - let generation = u64::from_le_bytes(bytes[21..29].try_into().map_err(|_| MemcardStatus::Corrupt)?); - let checksum = u32::from_le_bytes(bytes[29..33].try_into().map_err(|_| MemcardStatus::Corrupt)?); + let generation = + u64::from_le_bytes(bytes[21..29].try_into().map_err(|_| MemcardStatus::Corrupt)?); + let checksum = + u32::from_le_bytes(bytes[29..33].try_into().map_err(|_| MemcardStatus::Corrupt)?); let payload_size = u32::from_le_bytes(bytes[33..37].try_into().map_err(|_| MemcardStatus::Corrupt)?) as usize; if payload_size > MEMCARD_SLOT_CAPACITY_BYTES { diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs index 2d7375c4..5b597bd8 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs @@ -197,7 +197,7 @@ impl NativeInterface for VirtualMachineRuntime { let pan_raw = expect_int(args, 3)?; let pitch = expect_number(args, 4, "pitch")?; - if voice_id_raw < 0 || voice_id_raw >= 16 { + if !(0..16).contains(&voice_id_raw) { ret.push_int(AudioOpStatus::VoiceInvalid as i64); return Ok(()); } @@ -238,7 +238,7 @@ impl NativeInterface for VirtualMachineRuntime { _ => prometeu_hal::LoopMode::On, }; - if voice_id_raw < 0 || voice_id_raw >= 16 { + if !(0..16).contains(&voice_id_raw) { ret.push_int(AudioOpStatus::VoiceInvalid as i64); return Ok(()); } @@ -558,7 +558,7 @@ fn hex_decode(s: &str) -> Result, VmFault> { } let bytes = s.as_bytes(); - if bytes.len() % 2 != 0 { + if !bytes.len().is_multiple_of(2) { return Err(VmFault::Trap(TRAP_TYPE, "payload_hex must have even length".to_string())); } let mut out = Vec::with_capacity(bytes.len() / 2); diff --git a/files/config/Jenkinsfile b/files/config/Jenkinsfile index ec6c9cf8..ec1e1257 100644 --- a/files/config/Jenkinsfile +++ b/files/config/Jenkinsfile @@ -1,20 +1,57 @@ pipeline { - agent any + agent any + + environment { + CARGO_TERM_COLOR = 'always' + } stages { - stage('CI') { - steps { - withChecks(name: 'Rust CI', includeStage: true) { + stage('Build') { + steps { + withChecks(name: 'Test', includeStage: true) { sh ''' - set -e - which rustc - which cargo - rustc --version - cargo --version - make ci + set -eux + make ci ''' - } + } + publishHTML(target: [ + allowMissing: false, + alwaysLinkToLastBuild: true, + keepAll: true, + reportDir: 'target/llvm-cov/html', + reportFiles: 'index.html', + reportName: 'Rust Coverage HTML', + reportTitles: 'Coverage Report' + ]) + } + } // Test + stage('Coverage') { + steps { + sh ''' + set -eux + make cobertura + ''' + recordCoverage( + tools: [[parser: 'COBERTURA', pattern: 'target/llvm-cov/cobertura.xml']], + sourceCodeRetention: 'LAST_BUILD', + enabledForFailure: true, + failOnError: true, + checksAnnotationScope: 'MODIFIED_LINES', + checksName: 'Rust Coverage', + qualityGates: [ + [metric: 'LINE', baseline: 'MODIFIED_LINES', threshold: 20.0], + [metric: 'LINE', baseline: 'PROJECT', threshold: 20.0], + [metric: 'BRANCH', baseline: 'PROJECT', threshold: 20.0] + ] + ) } - } + } // Cobertura } + } + + post { + always { + archiveArtifacts artifacts: 'target/llvm-cov/**', fingerprint: true + } + } } \ No newline at end of file