Skip to content

Week 5 day 1#15

Open
Ngozistephen wants to merge 12 commits intoBloceducare:mainfrom
Ngozistephen:week-5-day-1
Open

Week 5 day 1#15
Ngozistephen wants to merge 12 commits intoBloceducare:mainfrom
Ngozistephen:week-5-day-1

Conversation

@Ngozistephen
Copy link

Task Submission PR

Student Info:

  • Registered Name: Ngozi Stephen
  • Week: 5
  • Day: 1

Task Details:

  • Task Name: Rust Scaffold cli
  • Task Description: It is a CLI Scaffolder that allows for an opinionated scaffolding of Rust Project

Checklist Before Submitting:

  • [ yes] My code follows the repository folder structure.
  • [ yes] I have properly named my files and folders.
  • [ yes] I have documented my code where necessary.
  • [yes ] I have tested my solution and ensured it works as expected.

Additional Comments:

If any, mention here.

Copilot AI review requested due to automatic review settings February 23, 2026 19:43
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 pull request contains multiple week submissions (Week 2, 3, 4, and 5) for a Rust learning curriculum. The primary focus is Week 5 Day 1, which introduces a Rust Scaffold CLI tool that generates opinionated project structures for Axum and Actix-web frameworks.

Changes:

  • Week 5 Day 1: New Rust Scaffold CLI project with template-based project generation for web frameworks
  • Week 4 Day 1: Blog API project using Axum with CRUD operations for blog posts
  • Week 3 Day 3: CLI grep-like tool for searching text in files
  • Week 2 submissions: Expense tracker and user input handling exercises

Reviewed changes

Copilot reviewed 36 out of 41 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/Cargo.toml Project manifest with invalid Rust edition "2024"
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/main.rs CLI entry point with command routing
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/cli.rs CLI argument parsing using clap
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/framework.rs Framework abstraction with significant code duplication
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/handlers.rs User interaction and prompt handling
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/services.rs File system operations for scaffolding
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/templates/mod.rs Shared template constants
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/templates/axum.rs Axum framework templates
submissions/week-5/day-1/stephenngozi-rust-scaffold-cli/src/templates/actix.rs Actix-web framework templates
submissions/week-4/day-1/stephen-ngozi-blog-project/Cargo.toml Blog project manifest with invalid edition
submissions/week-4/day-1/stephen-ngozi-blog-project/src/models.rs Data models with missing AppState definition
submissions/week-4/day-1/stephen-ngozi-blog-project/src/app_state.rs Disconnected AppState module
submissions/week-4/day-1/stephen-ngozi-blog-project/src/router.rs Route definitions with incorrect path syntax
submissions/week-4/day-1/stephen-ngozi-blog-project/src/config.rs Configuration with incorrect error variant usage
submissions/week-4/day-1/stephen-ngozi-blog-project/src/error.rs Error types with spelling errors
submissions/week-3/day-3/stephenngozi-build-cli-project/Cargo.toml CLI grep project with invalid edition
submissions/week-3/day-3/stephenngozi-build-cli-project/src/main.rs Main entry with spelling error
submissions/week-2/day-5/Stephen-Ngozi-Merkle-Tree/Cargo.toml Expense tracker with invalid edition
submissions/week-2/day-5/Stephen-Ngozi-Merkle-Tree/src/main.rs Main file with multiple spelling errors
submissions/week-2/day-3/Stephen-Ngozi-User-Input/Cargo.toml User input project with invalid edition

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

let id: u8 = id_input.trim().parse().expect("Please enter a valid ID");

if tracker.delete(id){
println!(" Your Expence is Deleted ");
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Spelling error: "Expence" should be "Expense".

Suggested change
println!(" Your Expence is Deleted ");
println!(" Your Expense is Deleted ");

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +40
tracker.save_to_file("stephen_expences.txt");
println!("Data saved to stephen_expences.txt");
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Spelling error: "expences" should be "expenses".

Suggested change
tracker.save_to_file("stephen_expences.txt");
println!("Data saved to stephen_expences.txt");
tracker.save_to_file("stephen_expenses.txt");
println!("Data saved to stephen_expenses.txt");

Copilot uses AI. Check for mistakes.
content: payload.content,
author_id: payload.author_id,
created_at: now,
updated_at:now
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Missing space after colon in struct field. The formatting should be "updated_at: now" for consistency with Rust style guidelines.

Suggested change
updated_at:now
updated_at: now

Copilot uses AI. Check for mistakes.
let args: Vec<String> = env::args().collect();

let config = Config::new(&args).unwrap_or_else(|err |{
eprintln!("Problem parsing argumemts: {}", err);
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Spelling error: "argumemts" should be "arguments".

Suggested change
eprintln!("Problem parsing argumemts: {}", err);
eprintln!("Problem parsing arguments: {}", err);

Copilot uses AI. Check for mistakes.
}
}
} else if input == "3" {
println!("Enter the ID of the Expence");
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Spelling error: "Expence" should be "Expense".

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +222
pub fn dependencies(&self) -> String {
match self {
Framework::Axum => {
r#"[dependencies]
# Core web framework built on Tokio — fast and ergonomic
axum = "0.7"

# Async runtime — required for all async Rust code
tokio = { version = "1", features = ["full"] }

# Tower middleware ecosystem (axum is built on top of tower)
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "trace"] }

# Serialization / Deserialization — JSON support
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# Environment variable management
dotenv = "0.15"

# Logging
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
"#
.to_string()
}

Framework::Actix => {
r#"[dependencies]
# Core web framework — high-performance, battle-tested
actix-web = "4"

# Tokio async runtime (actix-web uses it under the hood)
tokio = { version = "1", features = ["full"] }

# Middleware utilities for actix-web
actix-cors = "0.7"

# Serialization / Deserialization — JSON support
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# Environment variable management
dotenv = "0.15"

# Logging
env_logger = "0.11"
log = "0.4"
"#
.to_string()
}
}
}

// Returns the content of main.rs for each framework.
pub fn main_rs_content(&self, project_name: &str) -> String {
match self {
Framework::Axum => format!(
r#"mod handlers;
mod models;
mod router;
mod services;

use tracing_subscriber::{{EnvFilter, fmt}};

// CONCEPT: #[tokio::main] is a macro that sets up the Tokio async runtime.
// Without it, you can't use `async fn main()`.
#[tokio::main]
async fn main() {{
// Initialize tracing/logging
fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();

// Load environment variables from .env file
dotenv::dotenv().ok();

tracing::info!("Starting {} server...", "{project_name}");

// Build the router — all routes are registered in router/mod.rs
let app = router::create_router();

// Bind to address and start serving
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.expect("Failed to bind to port 3000");

tracing::info!("🚀 Server running at http://0.0.0.0:3000");

axum::serve(listener, app)
.await
.expect("Server error");
}}
"#,
project_name = project_name
),

Framework::Actix => format!(
r#"mod handlers;
mod models;
mod router;
mod services;

use actix_web::{{App, HttpServer}};

// CONCEPT: #[actix_web::main] sets up the Actix async runtime.
// Actix has its own runtime built on top of Tokio.
#[actix_web::main]
async fn main() -> std::io::Result<()> {{
// Initialize logger
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));

// Load environment variables from .env file
dotenv::dotenv().ok();

log::info!("Starting {} server...", "{project_name}");
log::info!("🚀 Server running at http://0.0.0.0:8080");

// HttpServer::new takes a closure that returns an App
// The move || closure captures environment for thread safety
HttpServer::new(move || {{
App::new()
.configure(router::configure_routes)
}})
.bind("0.0.0.0:8080")?
.run()
.await
}}
"#,
project_name = project_name
),
}
}

// Returns the router/mod.rs content
pub fn router_mod_content(&self) -> String {
match self {
Framework::Axum => {
r#"use axum::Router;
// Import your handlers here as you build them out.
// Example: use crate::handlers::health::health_check;

/// Creates and returns the main application Router.
/// Add all your routes here using `.route(path, method_handler)`.
pub fn create_router() -> Router {
Router::new()
// Example routes — uncomment and expand as needed:
// .route("/health", axum::routing::get(handlers::health_check))
// .route("/api/v1/users", axum::routing::get(handlers::users::list_users))
}
"#
.to_string()
}

Framework::Actix => {
r#"use actix_web::web;
// Import your handlers here as you build them out.
// Example: use crate::handlers::health::health_check;

/// Configures all routes for the Actix-web application.
/// Called in main.rs inside App::new().configure(...)
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
cfg
// Example routes — uncomment and expand as needed:
// .service(web::resource("/health").route(web::get().to(handlers::health_check)))
// .service(
// web::scope("/api/v1")
// .service(web::resource("/users").route(web::get().to(handlers::users::list_users)))
// )
;
}
"#
.to_string()
}
}
}


// Returns the handlers/mod.rs content
pub fn handlers_mod_content(&self) -> &'static str {
match self {
Framework::Axum => axum::HANDLERS_MOD,
Framework::Actix => actix::HANDLERS_MOD,
}
}

// Returns the .env content
pub fn env_content(&self) -> &'static str {
match self {
Framework::Axum => "RUST_LOG=info\nPORT=3000\n",
Framework::Actix => "RUST_LOG=info\nPORT=8080\n",
}
}
} No newline at end of file
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

There is significant code duplication between the framework.rs file and the template files. The dependencies method in framework.rs (lines 28-81) contains the exact same content as the DEPENDENCIES constants in templates/axum.rs and templates/actix.rs. Similarly, main_rs_content (lines 84-161), router_mod_content (lines 164-204) duplicate content from the template modules. This violates the DRY (Don't Repeat Yourself) principle and makes maintenance harder. Consider removing the duplicated code from framework.rs and instead using the constants from the templates module directly.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +31
use sqlx::PgPool;
use std::sync::Arc;



#[derive(Debug,Clone)]

// pub struct AppState {
// pub db_pool: PgPool,
// }
pub struct AppState {
pub authors: Arc<RwLock<HashMap<uuid::Uuid,Author>>>,
pub posts: Arc<RwLock<HashMap<uuid::Uuid, BlogPost>>>,
// next_id: Arc<RwLock<u64>>,
}

impl AppState {
pub fn new() -> Self {
Self {
authors: Arc::new(RwLock::new(seed_authors())),
posts: Arc::new(RwLock::new(HashMap::new())),
// next_id: Arc::new(RwLock::new(0u64)),
}
}
}

impl Default for AppState {
fn default() -> Self {
Self::new()
}
} No newline at end of file
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The app_state module is not declared in main.rs, so this file is not part of the compilation unit. The code in this file references types (RwLock, HashMap, Author, BlogPost) and a function (seed_authors) that are either not imported or not accessible. This will prevent the project from compiling. To fix this, either integrate this code into models.rs or add "mod app_state;" to main.rs and ensure all necessary imports are present.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +35
pub async fn insert_post (
state: &AppState,
payload: CreatePostRequest,)
-> Result<BlogPost, AppError>

{
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Missing space after comma in function parameters. The formatting should be "state: &AppState, payload: CreatePostRequest" for better readability and consistency with Rust style guidelines.

Suggested change
pub async fn insert_post (
state: &AppState,
payload: CreatePostRequest,)
-> Result<BlogPost, AppError>
{
pub async fn insert_post(
state: &AppState, payload: CreatePostRequest,
) -> Result<BlogPost, AppError>
{

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +92
fn seed_authors() -> HashMap<Uuid, Author> {
let authors = vec![
Author::new(
Uuid::new_v4(),
"Emeka Allison".to_string(),
"emekaallison4@gmail.com".to_string(),
),
Author::new(
Uuid::new_v4(),
"John Doe".to_string(),
"johndoe@mail.com".to_string(),
),
];

authors.into_iter().map(|a| (a.id, a)).collect()
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The AppState struct is not defined in this file, but it is imported from models in other files (e.g., handlers.rs, services.rs). The actual AppState definition exists in app_state.rs but that module is not connected to the main.rs module tree. Additionally, the seed_authors function defined on line 77 is used by AppState::new() in app_state.rs but is not accessible because it's in a different module. This will cause compilation errors. Consider either: 1) Moving AppState and seed_authors to this file and making seed_authors public, or 2) Adding app_state as a module in main.rs and adjusting imports accordingly.

Copilot uses AI. Check for mistakes.
InternalServerError(String),
#[error("Invalid Input, cannot be processed: {field} - {message}")]
UnProcessableEntity { field: String, message: String },
#[error("Environement Variable is missing: {0}")]
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Spelling error: "Environement" should be "Environment".

Suggested change
#[error("Environement Variable is missing: {0}")]
#[error("Environment Variable is missing: {0}")]

Copilot uses AI. Check for mistakes.
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