Skip to content

Commit 6362008

Browse files
committed
carrgo-rail: wired JUnit reporting in CI; added a proper utils.rs for paths/urls/etc. across platforms
1 parent e2392d6 commit 6362008

File tree

10 files changed

+228
-156
lines changed

10 files changed

+228
-156
lines changed

.github/actions-lock.yaml

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,36 @@
2626
actions/checkout:
2727
ref: v5.0.0
2828
sha: "08c6903cd8c0fde910a37f88322edcfb5dd907a8"
29-
updated: "2025-01-11T00:00:00Z"
29+
updated: "2025-11-15T04:25:54Z"
3030
notes: "Repository checkout - used in every workflow"
31-
3231
actions/upload-artifact:
3332
ref: v5.0.0
3433
sha: "330a01c490aca151604b8cf639adc76d48f6c5d4"
35-
updated: "2025-01-11T00:00:00Z"
34+
updated: "2025-11-15T04:25:55Z"
3635
notes: "Upload build artifacts and test results"
37-
36+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
37+
# Testing & Reporting
38+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
39+
mikepenz/action-junit-report:
40+
ref: v6.0.1
41+
sha: "e08919a3b1fb83a78393dfb775a9c37f17d8eea6"
42+
updated: "2025-11-15T04:25:56Z"
43+
notes: "Publish JUnit test reports as GitHub Checks"
3844
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3945
# Rust Toolchain & Ecosystem
4046
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
41-
4247
dtolnay/rust-toolchain:
4348
ref: master
44-
sha: "6d653acede28d24f02e3cd41383119e8b1b35921"
45-
updated: "2025-01-11T00:00:00Z"
49+
sha: "0f44b27771c32bda9f458f75a1e241b09791b331"
50+
updated: "2025-11-15T04:25:57Z"
4651
notes: "Rust toolchain installation - always tracks latest nightly"
47-
4852
taiki-e/install-action:
4953
ref: v2
50-
sha: "6f9c7cc51aa54b13cbcbd12f8bbf69d8ba405b4b"
51-
updated: "2025-01-11T00:00:00Z"
54+
sha: "0be4756f42223b67aa4b7df5effad59010cbf4b9"
55+
updated: "2025-11-15T04:25:57Z"
5256
notes: "Install cargo tools (nextest, just, deny, audit)"
53-
5457
Swatinem/rust-cache:
5558
ref: v2.8.1
5659
sha: "f13886b937689c021905a6b90929199931d60db1"
57-
updated: "2025-01-11T00:00:00Z"
60+
updated: "2025-11-15T04:25:58Z"
5861
notes: "GitHub runner Rust cache"

.github/actions/setup/action.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,37 @@ runs:
1515
# Install cargo tools FIRST, before Rust toolchain installation
1616
# This prevents Windows issues where massive toolchain updates interfere with cargo bin directory
1717
- name: Install just
18-
uses: taiki-e/install-action@6f9c7cc51aa54b13cbcbd12f8bbf69d8ba405b4b # v2
18+
uses: taiki-e/install-action@0be4756f42223b67aa4b7df5effad59010cbf4b9 # v2
1919
with:
2020
tool: just
2121

2222
- name: Install cargo-nextest
23-
uses: taiki-e/install-action@6f9c7cc51aa54b13cbcbd12f8bbf69d8ba405b4b # v2
23+
uses: taiki-e/install-action@0be4756f42223b67aa4b7df5effad59010cbf4b9 # v2
2424
with:
2525
tool: cargo-nextest
2626

2727
- name: Install cargo-deny
28-
uses: taiki-e/install-action@6f9c7cc51aa54b13cbcbd12f8bbf69d8ba405b4b # v2
28+
uses: taiki-e/install-action@0be4756f42223b67aa4b7df5effad59010cbf4b9 # v2
2929
with:
3030
tool: cargo-deny
3131

3232
- name: Install cargo-audit
33-
uses: taiki-e/install-action@6f9c7cc51aa54b13cbcbd12f8bbf69d8ba405b4b # v2
33+
uses: taiki-e/install-action@0be4756f42223b67aa4b7df5effad59010cbf4b9 # v2
3434
with:
3535
tool: cargo-audit
3636

3737
- name: Install cargo-semver-checks
38-
uses: taiki-e/install-action@6f9c7cc51aa54b13cbcbd12f8bbf69d8ba405b4b # v2
38+
uses: taiki-e/install-action@0be4756f42223b67aa4b7df5effad59010cbf4b9 # v2
3939
with:
4040
tool: cargo-semver-checks
4141

4242
- name: Install git-cliff
43-
uses: taiki-e/install-action@6f9c7cc51aa54b13cbcbd12f8bbf69d8ba405b4b # v2
43+
uses: taiki-e/install-action@0be4756f42223b67aa4b7df5effad59010cbf4b9 # v2
4444
with:
4545
tool: git-cliff
4646

4747
- name: Install Rust Nightly Toolchain
48-
uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
48+
uses: dtolnay/rust-toolchain@0f44b27771c32bda9f458f75a1e241b09791b331 # master
4949
with:
5050
toolchain: nightly
5151
components: clippy, rustfmt

.github/workflows/commit.yaml

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ env:
2222
# Lock down permissions to read-only by default
2323
permissions:
2424
contents: read
25+
checks: write # Required for publishing test reports
26+
pull-requests: write # Required for PR comments on test results
2527

2628
jobs:
2729
ci:
@@ -56,7 +58,9 @@ jobs:
5658

5759
steps:
5860
- name: Checkout
59-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
61+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
62+
with:
63+
persist-credentials: false
6064

6165
- name: Setup
6266
uses: ./.github/actions/setup
@@ -72,11 +76,30 @@ jobs:
7276
- name: Tests
7377
run: just test
7478

75-
- name: Upload Test Results (on failure)
79+
- name: Upload JUnit Test Report
80+
if: always()
81+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
82+
with:
83+
name: junit-report-${{ matrix.target.name }}
84+
path: junit.xml
85+
retention-days: 7
86+
if-no-files-found: ignore
87+
88+
- name: Publish Test Report
89+
if: always()
90+
uses: mikepenz/action-junit-report@e08919a3b1fb83a78393dfb775a9c37f17d8eea6 # v6.0.1
91+
with:
92+
report_paths: 'junit.xml'
93+
check_name: 'Test Results (${{ matrix.target.name }})'
94+
detailed_summary: true
95+
include_passed: false
96+
fail_on_failure: true
97+
98+
- name: Upload Nextest Results (on failure)
7699
if: failure()
77-
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
100+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
78101
with:
79-
name: test-results-${{ matrix.target.name }}
102+
name: nextest-results-${{ matrix.target.name }}
80103
path: target/nextest/
81104
retention-days: 7
82105
if-no-files-found: ignore

src/commands/split.rs

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,15 @@
11
use std::env;
22
use std::io::{self, Write};
3-
use std::path::Path;
43

54
use crate::commands::doctor;
65
use crate::core::config::RailConfig;
76
use crate::core::error::{ConfigError, RailError, RailResult};
87
use crate::core::plan::{Operation, OperationType, Plan};
98
use crate::core::split::{SplitConfig, Splitter};
109
use crate::ui::progress::{FileProgress, MultiProgress};
10+
use crate::utils;
1111
use rayon::prelude::*;
1212

13-
/// Check if a path is a local filesystem path (not a remote URL)
14-
///
15-
/// Returns true for:
16-
/// - Absolute paths on Unix: /path/to/repo
17-
/// - Absolute paths on Windows: C:\path\to\repo or C:/path/to/repo
18-
/// - Relative paths: ./path or ../path
19-
/// - UNC paths on Windows: \\server\share
20-
///
21-
/// Returns false for:
22-
/// - SSH URLs: [email protected]:user/repo.git
23-
/// - HTTPS URLs: <https://github.com/user/repo.git>
24-
fn is_local_path(path: &str) -> bool {
25-
let p = Path::new(path);
26-
27-
// Check for relative paths
28-
if path.starts_with("./") || path.starts_with("../") {
29-
return true;
30-
}
31-
32-
// Check for absolute paths (works on both Unix and Windows)
33-
if p.is_absolute() {
34-
return true;
35-
}
36-
37-
// Check for Windows UNC paths (\\server\share)
38-
#[cfg(target_os = "windows")]
39-
if path.starts_with("\\\\") {
40-
return true;
41-
}
42-
43-
// If it contains :// it's a URL
44-
if path.contains("://") {
45-
return false;
46-
}
47-
48-
// If it contains @ it's likely an SSH URL ([email protected]:user/repo.git)
49-
if path.contains('@') {
50-
return false;
51-
}
52-
53-
// Default to false for safety (require preflight checks)
54-
false
55-
}
56-
5713
/// Prompt user for confirmation
5814
fn prompt_for_confirmation(message: &str) -> RailResult<bool> {
5915
print!("\n{}: ", message);
@@ -111,7 +67,7 @@ pub fn run_split(
11167
}
11268

11369
// Check if all remotes are local paths (skip SSH checks for local testing)
114-
let all_local = crates_to_split_check.iter().all(|s| is_local_path(&s.remote));
70+
let all_local = crates_to_split_check.iter().all(|s| utils::is_local_path(&s.remote));
11571

11672
// Run preflight health checks before proceeding (skip for local-only operations)
11773
if !json && apply && !all_local {

src/commands/sync.rs

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::env;
2-
use std::path::Path;
32

43
use crate::commands::doctor;
54
use crate::core::config::RailConfig;
@@ -8,52 +7,9 @@ use crate::core::error::{ConfigError, RailError, RailResult};
87
use crate::core::plan::{Operation, OperationType, Plan};
98
use crate::core::sync::{SyncConfig, SyncDirection, SyncEngine, SyncResult};
109
use crate::ui::progress::{FileProgress, MultiProgress};
10+
use crate::utils;
1111
use rayon::prelude::*;
1212

13-
/// Check if a path is a local filesystem path (not a remote URL)
14-
///
15-
/// Returns true for:
16-
/// - Absolute paths on Unix: /path/to/repo
17-
/// - Absolute paths on Windows: C:\path\to\repo or C:/path/to/repo
18-
/// - Relative paths: ./path or ../path
19-
/// - UNC paths on Windows: \\server\share
20-
///
21-
/// Returns false for:
22-
/// - SSH URLs: [email protected]:user/repo.git
23-
/// - HTTPS URLs: <https://github.com/user/repo.git>
24-
fn is_local_path(path: &str) -> bool {
25-
let p = Path::new(path);
26-
27-
// Check for relative paths
28-
if path.starts_with("./") || path.starts_with("../") {
29-
return true;
30-
}
31-
32-
// Check for absolute paths (works on both Unix and Windows)
33-
if p.is_absolute() {
34-
return true;
35-
}
36-
37-
// Check for Windows UNC paths (\\server\share)
38-
#[cfg(target_os = "windows")]
39-
if path.starts_with("\\\\") {
40-
return true;
41-
}
42-
43-
// If it contains :// it's a URL
44-
if path.contains("://") {
45-
return false;
46-
}
47-
48-
// If it contains @ it's likely an SSH URL ([email protected]:user/repo.git)
49-
if path.contains('@') {
50-
return false;
51-
}
52-
53-
// Default to false for safety (require preflight checks)
54-
false
55-
}
56-
5713
/// Sync command parameters
5814
pub struct SyncParams {
5915
pub crate_name: Option<String>,
@@ -153,7 +109,7 @@ fn run_sync_impl(params: SyncParams) -> RailResult<()> {
153109
}
154110

155111
// Check if all remotes are local paths (skip SSH checks for local testing)
156-
let all_local = crates_to_sync_check.iter().all(|s| is_local_path(&s.remote));
112+
let all_local = crates_to_sync_check.iter().all(|s| utils::is_local_path(&s.remote));
157113

158114
// Run preflight health checks before proceeding (skip for local-only operations)
159115
if !json && apply && !all_local {

src/core/split.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::core::mapping::MappingStore;
1010
use crate::core::security::SecurityValidator;
1111
use crate::core::vcs::CommitInfo;
1212
use crate::core::vcs::SystemGit;
13+
use crate::utils;
1314

1415
/// Configuration for a split operation
1516
pub struct SplitConfig {
@@ -440,10 +441,7 @@ impl Splitter {
440441

441442
// Push to remote if URL is configured and is not a local file path
442443
if let Some(ref remote_url) = config.remote_url {
443-
// Check if this is a local file path (absolute path or relative)
444-
let is_local_path = remote_url.starts_with('/') || remote_url.starts_with("./") || remote_url.starts_with("../");
445-
446-
if !remote_url.is_empty() && !is_local_path {
444+
if !remote_url.is_empty() && !utils::is_local_path(remote_url) {
447445
println!("\n🚀 Pushing to remote...");
448446

449447
// Security checks before push
@@ -470,7 +468,7 @@ impl Splitter {
470468
println!(" ✅ Pushed to {}", remote_url);
471469
} else {
472470
println!("\n💾 Split repository created locally");
473-
if is_local_path {
471+
if utils::is_local_path(remote_url) {
474472
println!(" Note: Remote is a local path, skipping push");
475473
println!(
476474
" Local testing mode - split repo at: {}",

0 commit comments

Comments
 (0)