Skip to content

Rafaeljohn9/cargo tracker#2

Open
RafaelJohn9 wants to merge 5 commits intomainfrom
rafaeljohn9/cargo-tracker
Open

Rafaeljohn9/cargo tracker#2
RafaelJohn9 wants to merge 5 commits intomainfrom
rafaeljohn9/cargo-tracker

Conversation

@RafaelJohn9
Copy link
Owner

@RafaelJohn9 RafaelJohn9 commented Jun 10, 2025

Summary by CodeRabbit

  • New Features

    • Launched interactive Cargo Tracker CLI application for comprehensive shipment management.
    • Added support for creating and managing shipments with multiple packages per shipment.
    • Implemented shipment status tracking with automatic timestamp updates upon delivery.
    • Added filtering capabilities to view shipments by status (Pending, In Transit, Delivered, Lost).
    • Integrated report generation functionality for shipment data.
  • Chores

    • Added new Bit-torrent project scaffold.

…nd APIs to connect to the CLI\n

Signed-off-by: rafaeljohn9 <rafaeljohb@gmail.com>
Signed-off-by: rafaeljohn9 <rafaeljohb@gmail.com>
@RafaelJohn9 RafaelJohn9 requested a review from Copilot June 11, 2025 20:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a Cargo Tracker CLI application, introducing modules for managing shipments and packages.

  • Adds a ShipmentManager to create, update, and list shipments.
  • Introduces the Shipment and Package models with JSON serialization.
  • Develops a CLI interface in main.rs and updates Cargo.toml with new dependencies.

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
cargo-tracker/src/shipment_manager.rs Implements shipment management features with HashMap storage.
cargo-tracker/src/shipment.rs Defines data structures (Shipment, Package) and JSON serialization logic.
cargo-tracker/src/main.rs Creates the CLI commands for user interaction and shipment operations.
cargo-tracker/Cargo.toml Includes new dependencies (chrono, uuid, serde_json) required for functionality.

RafaelJohn9 and others added 2 commits June 11, 2025 23:46
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@coderabbitai
Copy link

coderabbitai bot commented Oct 22, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Two new Rust projects are introduced: a basic bit-torrent starter project with minimal scaffolding, and a fully-featured cargo-tracker CLI application featuring shipment tracking with model definitions (Shipment, Package, ShipmentStatus), interactive command handling, and a ShipmentManager for persistence and filtering operations.

Changes

Cohort / File(s) Summary
bit-torrent Project Setup
bit-torrent/Cargo.toml, bit-torrent/src/main.rs
New Rust project with manifest defining package metadata (name, version 0.1.0, edition 2024) and a basic main entry point printing "Hello World!" with a loop printing integers 1-9.
cargo-tracker Dependencies
cargo-tracker/Cargo.toml
Added three dependencies: chrono for timestamp handling, uuid (v4 feature) for unique identifiers, and serde_json for JSON serialization.
cargo-tracker Data Models
cargo-tracker/src/shipment.rs
New Shipment struct storing tracking_id, destination, status, timestamps, and Package list; ShipmentStatus enum with variants Pending, InTransit, Delivered, Lost; Package struct with UUID and description; includes constructors and JSON serialization via to_json_str().
cargo-tracker Manager
cargo-tracker/src/shipment_manager.rs
New ShipmentManager struct providing HashMap-backed storage with methods for creating shipments (auto-generating UUIDs when needed), retrieving by tracking_id, and filtering by optional status.
cargo-tracker CLI Implementation
cargo-tracker/src/main.rs
Interactive command-driven CLI loop with command parsing and handlers for help, add-shipment, add-package, update-status (with Delivered→arrival-time logic), view-shipment, list-shipments (with optional status filtering), generate-report (stub), clear screen, and exit; includes input validation and welcome message.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as Main CLI Loop
    participant Manager as ShipmentManager
    participant Shipment
    participant Package

    User->>CLI: Enter command
    CLI->>CLI: Parse command
    
    alt add-shipment
        CLI->>Manager: create_shipment()
        Manager->>Shipment: new()
        Shipment-->>Manager: Shipment instance
        Manager-->>CLI: &mut Shipment
    else add-package
        CLI->>Manager: get_shipment(tracking_id)
        Manager-->>CLI: &mut Shipment
        CLI->>Package: new(description)
        Package-->>CLI: Package instance
        CLI->>Shipment: add_package()
    else update-status
        CLI->>Manager: get_shipment(tracking_id)
        Manager-->>CLI: &mut Shipment
        alt status == Delivered
            Shipment->>Shipment: time_of_arrival = now()
        end
    else list-shipments
        CLI->>Manager: list_shipments(optional_filter)
        Manager-->>CLI: Vec<&Shipment>
        CLI->>CLI: Format and display
    end
    
    CLI-->>User: Display result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The diff spans multiple new modules with heterogeneous purposes (CLI, models, manager), featuring moderate logic density in command parsing and status transitions, but with repetitive patterns within each component and straightforward data structure definitions that somewhat offset complexity.

Poem

🐰 Packages hop and shipments track,

UUIDs march and JSON's back,

With chrono's time and statuses bright,

The cargo-tracker takes its flight! 📦

Two projects born to code's delight! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title "Rafaeljohn9/cargo tracker" reads as a branch or path name rather than a meaningful pull request title. While it mentions "cargo tracker" which is tangentially related to the primary changes in the PR (implementation of a Cargo Tracker CLI application with shipment management), it lacks descriptive language about what was actually accomplished. The inclusion of the username and absence of any action verbs or clear indication of scope (e.g., "Add", "Implement", "Create") makes it vague and uninformative for someone scanning the repository history. Consider revising the title to be more descriptive and actionable, such as "Implement Cargo Tracker CLI with shipment management" or "Add interactive cargo tracking application". This would better communicate to reviewers and future developers what functionality was introduced without requiring them to read the full changeset description.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rafaeljohn9/cargo-tracker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
cargo-tracker/src/main.rs (2)

53-61: Previous “time_of_arrival passed as departure” issue looks resolved.

Now using let time_of_departure = Some(chrono::Utc::now()); and passing it correctly. No action needed.


96-100: Unintended app exit on empty package description. Replace return with continue.

Returning here terminates the whole CLI loop.

-                        if description.trim().is_empty() {
-                            println!("Package description cannot be empty.");
-                            return;
-                        }
+                        if description.trim().is_empty() {
+                            println!("Package description cannot be empty.");
+                            continue;
+                        }
🧹 Nitpick comments (11)
cargo-tracker/src/main.rs (4)

63-77: Guard against empty package descriptions when adding to a new shipment.

Mirror the validation used in add-package to avoid empty entries.

-                    let package = Package::new(description);
-                    shipment.add_package(package);
-                    count += 1;
-                    package_num += 1;
+                    if description.trim().is_empty() {
+                        println!("Package description cannot be empty.");
+                    } else {
+                        let package = Package::new(description);
+                        shipment.add_package(package);
+                        count += 1;
+                        package_num += 1;
+                    }

166-177: Clarify invalid status filter message and behavior.

Currently an invalid filter prints “No shipments found…”, which is misleading. Prefer “Invalid status; showing all.”

-                    _ => {
-                        println!("No shipments found for status '{}'.", filter);
-                        None
-                    }
+                    _ => {
+                        println!(
+                            "Invalid status filter '{}'. Showing all shipments. Valid: Pending, InTransit, Delivered, Lost.",
+                            filter.trim()
+                        );
+                        None
+                    }

207-209: Flush after clearing screen (minor).

Ensure the ANSI clear takes effect immediately.

-                print!("\x1B[2J\x1B[1;1H");
+                print!("\x1B[2J\x1B[1;1H");
+                io::stdout().flush().ok();

210-213: Use break instead of process::exit(0) to enable proper resource cleanup.

The REPL loop (line 36) can exit cleanly with break, allowing Drop implementations to run. The codebase already uses break for similar patterns (line 71). Using exit(0) skips cleanup and is unnecessary here.

-                println!("Goodbye!");
-                exit(0);
+                println!("Goodbye!");
+                break;
cargo-tracker/src/shipment_manager.rs (2)

15-26: Avoid silent overwrite on duplicate tracking IDs; return a Result.

If tracking_id already exists, insert replaces the shipment. Consider failing fast.

-    ) -> &mut Shipment {
-        let id = tracking_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
-        let shipment = Shipment::new(status, destination, time_of_departure, id.clone());
-        self.shipments.insert(id.clone(), shipment);
-        self.shipments.get_mut(&id).unwrap()
+    ) -> Result<&mut Shipment, String> {
+        let id = tracking_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
+        if self.shipments.contains_key(&id) {
+            return Err(format!("Shipment with tracking ID '{}' already exists.", id));
+        }
+        let shipment = Shipment::new(status, destination, time_of_departure, id.clone());
+        self.shipments.insert(id.clone(), shipment);
+        Ok(self.shipments.get_mut(&id).expect("inserted above"))

Follow-up: update call sites to handle Result and print the error.


28-30: Split read-only and mutable getters for ergonomic borrows.

Requiring &mut self even for reads makes CLI code borrow mutably when unnecessary and limits parallel reads.

-    pub fn get_shipment(&mut self, tracking_id: &str) -> Option<&mut Shipment> {
-        self.shipments.get_mut(tracking_id)
-    }
+    pub fn get_shipment(&self, tracking_id: &str) -> Option<&Shipment> {
+        self.shipments.get(tracking_id)
+    }
+
+    pub fn get_shipment_mut(&mut self, tracking_id: &str) -> Option<&mut Shipment> {
+        self.shipments.get_mut(tracking_id)
+    }

Additional changes:

  • In main.rs where you only read (existence checks, view), switch to get_shipment.
  • Where you mutate (add-package, update-status), use get_shipment_mut.

I can push the corresponding main.rs diff if you want.

cargo-tracker/Cargo.toml (1)

6-11: Move test-only crates to [dev-dependencies].

assert_cmd and predicates are used only in test files and should not be included in release builds.

-[dependencies]
-assert_cmd = "2"
-predicates = "2"
-chrono = "0.4"
-uuid = { version = "1", features = ["v4"] }
-serde_json = "1"
+[dependencies]
+chrono = "0.4"
+uuid = { version = "1", features = ["v4"] }
+serde_json = "1"
+
+[dev-dependencies]
+assert_cmd = "2"
+predicates = "2"
cargo-tracker/src/shipment.rs (4)

1-3: Consider using serde for serialization instead of manual JSON construction.

The imports currently support manual JSON building via serde_json::json!. For better maintainability and type safety, consider using serde's Serialize and Deserialize derives instead.

Add serde to your imports:

 use chrono::{DateTime, Utc};
-use serde_json::json;
+use serde::{Deserialize, Serialize};
 use uuid::Uuid;

Then derive Serialize on your types (see subsequent comments for full refactor).


5-13: Consider additional derives for Shipment.

The Shipment struct only derives Debug, but adding Clone would be beneficial for common operations like storing in collections or passing around. While all fields are currently public, consider whether encapsulation would be appropriate for your use case.

-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct Shipment {

16-30: Consider adding input validation.

The constructor accepts tracking_id and destination without validation. Empty strings or whitespace-only values could lead to invalid shipments.

 pub fn new(
     status: ShipmentStatus,
     destination: String,
     time_of_departure: Option<DateTime<Utc>>,
     tracking_id: String,
 ) -> Self {
+    if tracking_id.trim().is_empty() {
+        panic!("tracking_id cannot be empty");
+    }
+    if destination.trim().is_empty() {
+        panic!("destination cannot be empty");
+    }
     Self {
         packages: Vec::new(),
         tracking_id,
         destination,
         status,
         time_of_departure,
         time_of_arrival: None,
     }
 }

Alternatively, return a Result<Self, String> for more graceful error handling.


69-73: Consider adding PartialEq derive.

The Package struct is well-structured. Adding PartialEq would enable equality comparisons, which can be useful for testing.

-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct Package {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae58435 and a13cac8.

📒 Files selected for processing (6)
  • bit-torrent/Cargo.toml (1 hunks)
  • bit-torrent/src/main.rs (1 hunks)
  • cargo-tracker/Cargo.toml (1 hunks)
  • cargo-tracker/src/main.rs (1 hunks)
  • cargo-tracker/src/shipment.rs (1 hunks)
  • cargo-tracker/src/shipment_manager.rs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
cargo-tracker/src/shipment_manager.rs (1)
cargo-tracker/src/shipment.rs (2)
  • new (16-30)
  • new (76-81)
cargo-tracker/src/main.rs (2)
cargo-tracker/src/shipment.rs (3)
  • new (16-30)
  • new (76-81)
  • packages (37-46)
cargo-tracker/src/shipment_manager.rs (1)
  • new (9-13)
cargo-tracker/src/shipment.rs (1)
cargo-tracker/src/shipment_manager.rs (1)
  • new (9-13)
🔇 Additional comments (5)
bit-torrent/Cargo.toml (2)

4-4: Verify CI and local toolchain support Rust 1.85 or later.

Rust 2024 edition requires Rust 1.85 or newer. All three crates in this repository already use edition = "2024", and Rust 1.85 was released with edition 2024. Ensure your CI configuration and developer toolchains meet this minimum version requirement, or builds will fail.


1-6: No workspace exists; bit-torrent is a standalone package.

The repository has no root Cargo.toml with [workspace] configuration. The three packages (bit-torrent, cargo-tracker, ratatui) are independent sibling directories, not workspace members. The workspace membership check in the original comment is not applicable here.

Likely an incorrect or invalid review comment.

cargo-tracker/src/shipment.rs (3)

32-34: LGTM!

The add_package method is straightforward and correct.


61-67: LGTM!

The ShipmentStatus enum variants are well-chosen and appropriately cover the shipment lifecycle. The derives (Debug, Clone, PartialEq) are suitable for this enum.


75-81: LGTM!

The Package::new constructor correctly generates a unique UUID v4 for each package instance.

Comment on lines +4 to +6
for i in 1..10{
println!("i: {}",i);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Range excludes 10 (minor off-by-one).

1..10 iterates 1..=9. If you intended to include 10, use an inclusive range.

-    for i in 1..10{
+    for i in 1..=10 {
         println!("i: {}",i);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for i in 1..10{
println!("i: {}",i);
}
for i in 1..=10 {
println!("i: {}",i);
}
🤖 Prompt for AI Agents
In bit-torrent/src/main.rs around lines 4 to 6, the loop uses an exclusive range
1..10 which iterates 1 through 9; to include 10 change the range to an inclusive
range 1..=10 (or if exclusion was intended, leave as-is); update the range
expression accordingly so the loop covers the intended bounds.

Comment on lines +124 to +130
_ => {
println!(
"Error: Invalid status. Valid options are: Pending, InTransit, Delivered, Lost."
);
return;
}
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not exit the CLI on invalid status; continue the loop.

return ends the program. Stay in REPL and prompt again.

-                            _ => {
-                                println!(
-                                    "Error: Invalid status. Valid options are: Pending, InTransit, Delivered, Lost."
-                                );
-                                return;
-                            }
+                            _ => {
+                                println!(
+                                    "Error: Invalid status. Valid options are: Pending, InTransit, Delivered, Lost."
+                                );
+                                continue;
+                            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_ => {
println!(
"Error: Invalid status. Valid options are: Pending, InTransit, Delivered, Lost."
);
return;
}
};
_ => {
println!(
"Error: Invalid status. Valid options are: Pending, InTransit, Delivered, Lost."
);
continue;
}
};
🤖 Prompt for AI Agents
In cargo-tracker/src/main.rs around lines 124 to 130 the code prints an error on
invalid status and then calls return which exits the CLI; instead remove the
return and continue the input loop so the REPL keeps running. Replace the early
return with a continue (or otherwise loop-continue control flow) so after
printing the error the program re-prompts the user rather than terminating.

Comment on lines +36 to +58
pub fn to_json_str(&self) -> String {
let packages_json = self
.packages
.iter()
.map(|p| {
json!({
"id": p.id.to_string(),
"description": p.description,
})
})
.collect::<Vec<_>>();

let json_obj = json!({
"tracking_id": self.tracking_id,
"destination": self.destination,
"status": format!("{:?}", self.status),
"time_of_departure": self.time_of_departure.map(|t| t.to_rfc3339()),
"time_of_arrival": self.time_of_arrival.map(|t| t.to_rfc3339()),
"packages": packages_json,
});

json_obj.to_string()
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Refactor to use serde's Serialize derive instead of manual JSON construction.

Manually building JSON is error-prone and harder to maintain. Since serde_json is already a dependency, leverage serde's Serialize derive for type-safe, automatic serialization. This also addresses the improper use of Debug format for the status enum on line 51.

Add serde to Cargo.toml if not already present with the derive feature:

serde = { version = "1", features = ["derive"] }

Then refactor the structs:

+use serde::{Deserialize, Serialize};
 use chrono::{DateTime, Utc};
-use serde_json::json;
 use uuid::Uuid;

-#[derive(Debug)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct Shipment {
     pub tracking_id: String,
     pub destination: String,
     pub packages: Vec<Package>,
     pub status: ShipmentStatus,
     pub time_of_departure: Option<DateTime<Utc>>,
     pub time_of_arrival: Option<DateTime<Utc>>,
 }
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub enum ShipmentStatus {
     Pending,
     InTransit,
     Delivered,
     Lost,
 }
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct Package {
     pub id: Uuid,
     pub description: String,
 }

Replace the entire to_json_str method:

     pub fn to_json_str(&self) -> String {
-        let packages_json = self
-            .packages
-            .iter()
-            .map(|p| {
-                json!({
-                    "id": p.id.to_string(),
-                    "description": p.description,
-                })
-            })
-            .collect::<Vec<_>>();
-
-        let json_obj = json!({
-            "tracking_id": self.tracking_id,
-            "destination": self.destination,
-            "status": format!("{:?}", self.status),
-            "time_of_departure": self.time_of_departure.map(|t| t.to_rfc3339()),
-            "time_of_arrival": self.time_of_arrival.map(|t| t.to_rfc3339()),
-            "packages": packages_json,
-        });
-
-        json_obj.to_string()
+        serde_json::to_string(self).unwrap_or_else(|_| String::from("{}"))
     }

@RafaelJohn9 RafaelJohn9 force-pushed the rafaeljohn9/cargo-tracker branch from a13cac8 to 3714969 Compare October 26, 2025 08:34
@github-actions
Copy link

🚀 Shipment On Schedule! cargo-tracker Tests Passed!

📦 All packages inspected and cleared for delivery.

✅ The cargo is stable, the manifest is clean, and we’re on track for a smooth merge!

Code like cargo: well-packed, clearly labeled, and always ready for delivery.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants