fix: single source of truth for version across crate and tests
Replace all hardcoded "1.1.0" version strings with env!("CARGO_PKG_VERSION")
in src/, so Cargo.toml is the sole source for the built binary. Tests
intentionally use a separate hardcoded constant in tests/common.rs to act
as a canary — they will fail on a version bump until manually updated.
- src/project/mod.rs: add WEEVIL_VERSION const, wire into Tera context,
generated README, and .weevil-version marker
- tests/common.rs: new file, holds EXPECTED_VERSION for all test crates
- tests/{integration,project_lifecycle,unit/config_tests}.rs: pull from
common instead of env! or inline literals
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "weevil"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0-beta.1"
|
||||
edition = "2021"
|
||||
authors = ["Eric Ratliff <eric@intrepidfusion.com>"]
|
||||
authors = ["Eric Ratliff <eric@nxlearn.net>"]
|
||||
description = "FTC robotics project generator - bores into complexity, emerges with clean code"
|
||||
license = "MIT"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// File: src/lib.rs
|
||||
// Library interface for testing
|
||||
|
||||
pub mod version;
|
||||
pub mod sdk;
|
||||
pub mod project;
|
||||
pub mod commands;
|
||||
|
||||
69
src/main.rs
69
src/main.rs
@@ -1,6 +1,7 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use colored::*;
|
||||
use anyhow::Result;
|
||||
use weevil::version::WEEVIL_VERSION;
|
||||
|
||||
mod commands;
|
||||
mod sdk;
|
||||
@@ -9,9 +10,12 @@ mod templates;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "weevil")]
|
||||
#[command(author = "Eric Barch <eric@intrepidfusion.com>")]
|
||||
#[command(version = "1.0.0")]
|
||||
#[command(about = "FTC robotics project generator - bores into complexity, emerges with clean code", long_about = None)]
|
||||
#[command(author = "Eric Ratliff <eric@nxlearn.net>")]
|
||||
#[command(version = WEEVIL_VERSION)]
|
||||
#[command(
|
||||
about = "FTC robotics project generator - bores into complexity, emerges with clean code",
|
||||
long_about = None
|
||||
)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
@@ -23,71 +27,71 @@ enum Commands {
|
||||
New {
|
||||
/// Name of the robot project
|
||||
name: String,
|
||||
|
||||
|
||||
/// Path to FTC SDK (optional, will auto-detect or download)
|
||||
#[arg(long)]
|
||||
ftc_sdk: Option<String>,
|
||||
|
||||
|
||||
/// Path to Android SDK (optional, will auto-detect or download)
|
||||
#[arg(long)]
|
||||
android_sdk: Option<String>,
|
||||
},
|
||||
|
||||
|
||||
/// Check system health and diagnose issues
|
||||
Doctor,
|
||||
|
||||
|
||||
/// Setup development environment (system or project)
|
||||
Setup {
|
||||
/// Path to project directory (optional - without it, sets up system)
|
||||
path: Option<String>,
|
||||
},
|
||||
|
||||
|
||||
/// Remove Weevil-installed SDKs and dependencies
|
||||
Uninstall {
|
||||
/// Show what would be removed without actually removing anything
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
|
||||
|
||||
/// Remove only specific items by number (use --dry-run first to see the list)
|
||||
#[arg(long, value_name = "NUM", num_args = 1..)]
|
||||
only: Option<Vec<usize>>,
|
||||
},
|
||||
|
||||
|
||||
/// Upgrade an existing project to the latest generator version
|
||||
Upgrade {
|
||||
/// Path to the project directory
|
||||
path: String,
|
||||
},
|
||||
|
||||
|
||||
/// Build and deploy project to Control Hub
|
||||
Deploy {
|
||||
/// Path to the project directory
|
||||
path: String,
|
||||
|
||||
|
||||
/// Force USB connection
|
||||
#[arg(long)]
|
||||
usb: bool,
|
||||
|
||||
|
||||
/// Force WiFi connection
|
||||
#[arg(long)]
|
||||
wifi: bool,
|
||||
|
||||
|
||||
/// Custom IP address
|
||||
#[arg(short, long)]
|
||||
ip: Option<String>,
|
||||
},
|
||||
|
||||
|
||||
/// Manage SDKs (FTC and Android)
|
||||
Sdk {
|
||||
#[command(subcommand)]
|
||||
command: SdkCommands,
|
||||
},
|
||||
|
||||
|
||||
/// Show or update project configuration
|
||||
Config {
|
||||
/// Path to the project directory
|
||||
path: String,
|
||||
|
||||
|
||||
/// Set FTC SDK path for this project
|
||||
#[arg(long, value_name = "PATH")]
|
||||
set_sdk: Option<String>,
|
||||
@@ -98,10 +102,10 @@ enum Commands {
|
||||
enum SdkCommands {
|
||||
/// Install required SDKs
|
||||
Install,
|
||||
|
||||
|
||||
/// Show SDK status and locations
|
||||
Status,
|
||||
|
||||
|
||||
/// Update SDKs to latest versions
|
||||
Update,
|
||||
}
|
||||
@@ -110,11 +114,11 @@ fn main() -> Result<()> {
|
||||
// Enable colors on Windows
|
||||
#[cfg(windows)]
|
||||
colored::control::set_virtual_terminal(true).ok();
|
||||
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
||||
print_banner();
|
||||
|
||||
|
||||
match cli.command {
|
||||
Commands::New { name, ftc_sdk, android_sdk } => {
|
||||
commands::new::create_project(&name, ftc_sdk.as_deref(), android_sdk.as_deref())
|
||||
@@ -134,13 +138,11 @@ fn main() -> Result<()> {
|
||||
Commands::Deploy { path, usb, wifi, ip } => {
|
||||
commands::deploy::deploy_project(&path, usb, wifi, ip.as_deref())
|
||||
}
|
||||
Commands::Sdk { command } => {
|
||||
match command {
|
||||
SdkCommands::Install => commands::sdk::install_sdks(),
|
||||
SdkCommands::Status => commands::sdk::show_status(),
|
||||
SdkCommands::Update => commands::sdk::update_sdks(),
|
||||
}
|
||||
}
|
||||
Commands::Sdk { command } => match command {
|
||||
SdkCommands::Install => commands::sdk::install_sdks(),
|
||||
SdkCommands::Status => commands::sdk::show_status(),
|
||||
SdkCommands::Update => commands::sdk::update_sdks(),
|
||||
},
|
||||
Commands::Config { path, set_sdk } => {
|
||||
if let Some(sdk_path) = set_sdk {
|
||||
commands::config::set_sdk(&path, &sdk_path)
|
||||
@@ -153,8 +155,13 @@ fn main() -> Result<()> {
|
||||
|
||||
fn print_banner() {
|
||||
println!("{}", "═══════════════════════════════════════════════════════════".bright_cyan());
|
||||
println!("{}", " 🪲 Weevil - FTC Project Generator v1.0.0".bright_cyan().bold());
|
||||
println!(
|
||||
"{}",
|
||||
format!(" 🪲 Weevil - FTC Project Generator v{}", WEEVIL_VERSION)
|
||||
.bright_cyan()
|
||||
.bold()
|
||||
);
|
||||
println!("{}", " Nexus Workshops LLC".bright_cyan());
|
||||
println!("{}", "═══════════════════════════════════════════════════════════".bright_cyan());
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ use std::path::{Path, PathBuf};
|
||||
use std::fs;
|
||||
use anyhow::{Result, Context, bail};
|
||||
|
||||
const WEEVIL_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ProjectConfig {
|
||||
pub project_name: String,
|
||||
@@ -24,7 +26,7 @@ impl ProjectConfig {
|
||||
|
||||
Ok(Self {
|
||||
project_name: project_name.to_string(),
|
||||
weevil_version: "1.0.0".to_string(),
|
||||
weevil_version: WEEVIL_VERSION.to_string(),
|
||||
ftc_sdk_path,
|
||||
ftc_sdk_version,
|
||||
android_sdk_path,
|
||||
|
||||
@@ -7,6 +7,8 @@ use git2::Repository;
|
||||
|
||||
use crate::sdk::SdkConfig;
|
||||
|
||||
const WEEVIL_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
pub mod deployer;
|
||||
pub mod config;
|
||||
|
||||
@@ -68,7 +70,7 @@ impl ProjectBuilder {
|
||||
let mut _context = TeraContext::new();
|
||||
_context.insert("project_name", &self.name);
|
||||
_context.insert("sdk_dir", &sdk_config.ftc_sdk_path.to_string_lossy());
|
||||
_context.insert("generator_version", "1.0.0");
|
||||
_context.insert("generator_version", WEEVIL_VERSION);
|
||||
|
||||
self.create_project_files(project_path, sdk_config)?;
|
||||
|
||||
@@ -84,7 +86,7 @@ impl ProjectBuilder {
|
||||
let readme = format!(
|
||||
r#"# {}
|
||||
|
||||
FTC Robot Project generated by Weevil v1.0.0
|
||||
FTC Robot Project generated by Weevil v{}
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
@@ -111,7 +113,7 @@ deploy.bat
|
||||
2. Test locally: `./gradlew test`
|
||||
3. Deploy: `./deploy.sh` (or `deploy.bat` on Windows)
|
||||
"#,
|
||||
self.name
|
||||
self.name, WEEVIL_VERSION
|
||||
);
|
||||
fs::write(project_path.join("README.md"), readme)?;
|
||||
|
||||
@@ -120,7 +122,7 @@ deploy.bat
|
||||
fs::write(project_path.join(".gitignore"), gitignore)?;
|
||||
|
||||
// Version marker
|
||||
fs::write(project_path.join(".weevil-version"), "1.0.0")?;
|
||||
fs::write(project_path.join(".weevil-version"), WEEVIL_VERSION)?;
|
||||
|
||||
// build.gradle.kts - Pure Java with deployToSDK task
|
||||
// Escape backslashes for Windows paths in Kotlin strings
|
||||
|
||||
1
src/version.rs
Normal file
1
src/version.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub const WEEVIL_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
3
tests/common.rs
Normal file
3
tests/common.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
// Intentionally hardcoded. When you bump the version in Cargo.toml,
|
||||
// tests will fail here until you update this to match.
|
||||
pub const EXPECTED_VERSION: &str = "1.1.0-beta.1";
|
||||
@@ -2,6 +2,10 @@ use assert_cmd::prelude::*;
|
||||
use predicates::prelude::*;
|
||||
use std::process::Command;
|
||||
|
||||
#[path = "common.rs"]
|
||||
mod common;
|
||||
use common::EXPECTED_VERSION;
|
||||
|
||||
#[path = "integration/environment_tests.rs"]
|
||||
mod environment_tests;
|
||||
|
||||
@@ -25,7 +29,7 @@ fn test_version_command() {
|
||||
|
||||
cmd.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("1.0.0"));
|
||||
.stdout(predicate::str::contains(EXPECTED_VERSION));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -6,6 +6,10 @@ use std::fs;
|
||||
use weevil::project::{ProjectBuilder, ProjectConfig};
|
||||
use weevil::sdk::SdkConfig;
|
||||
|
||||
#[path = "common.rs"]
|
||||
mod common;
|
||||
use common::EXPECTED_VERSION;
|
||||
|
||||
// Note: These tests use the actual FTC SDK if available, or skip if not
|
||||
// For true unit testing with mocks, we'd need to refactor to use dependency injection
|
||||
|
||||
@@ -26,7 +30,7 @@ fn test_config_create_and_save() {
|
||||
assert_eq!(config.project_name, "test-robot");
|
||||
assert_eq!(config.ftc_sdk_path, sdk_path);
|
||||
assert_eq!(config.android_sdk_path, android_sdk_path);
|
||||
assert_eq!(config.weevil_version, "1.0.0");
|
||||
assert_eq!(config.weevil_version, EXPECTED_VERSION);
|
||||
|
||||
// Save and reload
|
||||
let project_path = temp_dir.path().join("project");
|
||||
@@ -60,7 +64,7 @@ fn test_config_toml_format() {
|
||||
let content = fs::read_to_string(project_path.join(".weevil.toml")).unwrap();
|
||||
|
||||
assert!(content.contains("project_name = \"my-robot\""));
|
||||
assert!(content.contains("weevil_version = \"1.0.0\""));
|
||||
assert!(content.contains(&format!("weevil_version = \"{}\"", EXPECTED_VERSION)));
|
||||
assert!(content.contains("ftc_sdk_path"));
|
||||
assert!(content.contains("ftc_sdk_version"));
|
||||
assert!(content.contains("android_sdk_path"));
|
||||
|
||||
@@ -6,6 +6,10 @@ use std::path::PathBuf;
|
||||
use tempfile::TempDir;
|
||||
use std::fs;
|
||||
|
||||
#[path = "../common.rs"]
|
||||
mod common;
|
||||
use common::EXPECTED_VERSION;
|
||||
|
||||
#[test]
|
||||
fn test_config_create_and_save() {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
@@ -15,7 +19,7 @@ fn test_config_create_and_save() {
|
||||
|
||||
assert_eq!(config.project_name, "test-robot");
|
||||
assert_eq!(config.ftc_sdk_path, sdk_path);
|
||||
assert_eq!(config.weevil_version, "1.0.0");
|
||||
assert_eq!(config.weevil_version, EXPECTED_VERSION);
|
||||
|
||||
// Save and reload
|
||||
config.save(temp_dir.path()).unwrap();
|
||||
@@ -45,7 +49,7 @@ fn test_config_toml_format() {
|
||||
let content = fs::read_to_string(temp_dir.path().join(".weevil.toml")).unwrap();
|
||||
|
||||
assert!(content.contains("project_name = \"my-robot\""));
|
||||
assert!(content.contains("weevil_version = \"1.0.0\""));
|
||||
assert!(content.contains(&format!("weevil_version = \"{}\"", EXPECTED_VERSION)));
|
||||
assert!(content.contains("ftc_sdk_path"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user