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]
|
[package]
|
||||||
name = "weevil"
|
name = "weevil"
|
||||||
version = "1.0.0"
|
version = "1.1.0-beta.1"
|
||||||
edition = "2021"
|
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"
|
description = "FTC robotics project generator - bores into complexity, emerges with clean code"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// File: src/lib.rs
|
// File: src/lib.rs
|
||||||
// Library interface for testing
|
// Library interface for testing
|
||||||
|
|
||||||
|
pub mod version;
|
||||||
pub mod sdk;
|
pub mod sdk;
|
||||||
pub mod project;
|
pub mod project;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
|||||||
23
src/main.rs
23
src/main.rs
@@ -1,6 +1,7 @@
|
|||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use colored::*;
|
use colored::*;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use weevil::version::WEEVIL_VERSION;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod sdk;
|
mod sdk;
|
||||||
@@ -9,9 +10,12 @@ mod templates;
|
|||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "weevil")]
|
#[command(name = "weevil")]
|
||||||
#[command(author = "Eric Barch <eric@intrepidfusion.com>")]
|
#[command(author = "Eric Ratliff <eric@nxlearn.net>")]
|
||||||
#[command(version = "1.0.0")]
|
#[command(version = WEEVIL_VERSION)]
|
||||||
#[command(about = "FTC robotics project generator - bores into complexity, emerges with clean code", long_about = None)]
|
#[command(
|
||||||
|
about = "FTC robotics project generator - bores into complexity, emerges with clean code",
|
||||||
|
long_about = None
|
||||||
|
)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Commands,
|
command: Commands,
|
||||||
@@ -134,13 +138,11 @@ fn main() -> Result<()> {
|
|||||||
Commands::Deploy { path, usb, wifi, ip } => {
|
Commands::Deploy { path, usb, wifi, ip } => {
|
||||||
commands::deploy::deploy_project(&path, usb, wifi, ip.as_deref())
|
commands::deploy::deploy_project(&path, usb, wifi, ip.as_deref())
|
||||||
}
|
}
|
||||||
Commands::Sdk { command } => {
|
Commands::Sdk { command } => match command {
|
||||||
match command {
|
|
||||||
SdkCommands::Install => commands::sdk::install_sdks(),
|
SdkCommands::Install => commands::sdk::install_sdks(),
|
||||||
SdkCommands::Status => commands::sdk::show_status(),
|
SdkCommands::Status => commands::sdk::show_status(),
|
||||||
SdkCommands::Update => commands::sdk::update_sdks(),
|
SdkCommands::Update => commands::sdk::update_sdks(),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
Commands::Config { path, set_sdk } => {
|
Commands::Config { path, set_sdk } => {
|
||||||
if let Some(sdk_path) = set_sdk {
|
if let Some(sdk_path) = set_sdk {
|
||||||
commands::config::set_sdk(&path, &sdk_path)
|
commands::config::set_sdk(&path, &sdk_path)
|
||||||
@@ -153,7 +155,12 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
fn print_banner() {
|
fn print_banner() {
|
||||||
println!("{}", "═══════════════════════════════════════════════════════════".bright_cyan());
|
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!("{}", " Nexus Workshops LLC".bright_cyan());
|
||||||
println!("{}", "═══════════════════════════════════════════════════════════".bright_cyan());
|
println!("{}", "═══════════════════════════════════════════════════════════".bright_cyan());
|
||||||
println!();
|
println!();
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use anyhow::{Result, Context, bail};
|
use anyhow::{Result, Context, bail};
|
||||||
|
|
||||||
|
const WEEVIL_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct ProjectConfig {
|
pub struct ProjectConfig {
|
||||||
pub project_name: String,
|
pub project_name: String,
|
||||||
@@ -24,7 +26,7 @@ impl ProjectConfig {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
project_name: project_name.to_string(),
|
project_name: project_name.to_string(),
|
||||||
weevil_version: "1.0.0".to_string(),
|
weevil_version: WEEVIL_VERSION.to_string(),
|
||||||
ftc_sdk_path,
|
ftc_sdk_path,
|
||||||
ftc_sdk_version,
|
ftc_sdk_version,
|
||||||
android_sdk_path,
|
android_sdk_path,
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use git2::Repository;
|
|||||||
|
|
||||||
use crate::sdk::SdkConfig;
|
use crate::sdk::SdkConfig;
|
||||||
|
|
||||||
|
const WEEVIL_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
pub mod deployer;
|
pub mod deployer;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|
||||||
@@ -68,7 +70,7 @@ impl ProjectBuilder {
|
|||||||
let mut _context = TeraContext::new();
|
let mut _context = TeraContext::new();
|
||||||
_context.insert("project_name", &self.name);
|
_context.insert("project_name", &self.name);
|
||||||
_context.insert("sdk_dir", &sdk_config.ftc_sdk_path.to_string_lossy());
|
_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)?;
|
self.create_project_files(project_path, sdk_config)?;
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ impl ProjectBuilder {
|
|||||||
let readme = format!(
|
let readme = format!(
|
||||||
r#"# {}
|
r#"# {}
|
||||||
|
|
||||||
FTC Robot Project generated by Weevil v1.0.0
|
FTC Robot Project generated by Weevil v{}
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
```bash
|
```bash
|
||||||
@@ -111,7 +113,7 @@ deploy.bat
|
|||||||
2. Test locally: `./gradlew test`
|
2. Test locally: `./gradlew test`
|
||||||
3. Deploy: `./deploy.sh` (or `deploy.bat` on Windows)
|
3. Deploy: `./deploy.sh` (or `deploy.bat` on Windows)
|
||||||
"#,
|
"#,
|
||||||
self.name
|
self.name, WEEVIL_VERSION
|
||||||
);
|
);
|
||||||
fs::write(project_path.join("README.md"), readme)?;
|
fs::write(project_path.join("README.md"), readme)?;
|
||||||
|
|
||||||
@@ -120,7 +122,7 @@ deploy.bat
|
|||||||
fs::write(project_path.join(".gitignore"), gitignore)?;
|
fs::write(project_path.join(".gitignore"), gitignore)?;
|
||||||
|
|
||||||
// Version marker
|
// 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
|
// build.gradle.kts - Pure Java with deployToSDK task
|
||||||
// Escape backslashes for Windows paths in Kotlin strings
|
// 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 predicates::prelude::*;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
#[path = "common.rs"]
|
||||||
|
mod common;
|
||||||
|
use common::EXPECTED_VERSION;
|
||||||
|
|
||||||
#[path = "integration/environment_tests.rs"]
|
#[path = "integration/environment_tests.rs"]
|
||||||
mod environment_tests;
|
mod environment_tests;
|
||||||
|
|
||||||
@@ -25,7 +29,7 @@ fn test_version_command() {
|
|||||||
|
|
||||||
cmd.assert()
|
cmd.assert()
|
||||||
.success()
|
.success()
|
||||||
.stdout(predicate::str::contains("1.0.0"));
|
.stdout(predicate::str::contains(EXPECTED_VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ use std::fs;
|
|||||||
use weevil::project::{ProjectBuilder, ProjectConfig};
|
use weevil::project::{ProjectBuilder, ProjectConfig};
|
||||||
use weevil::sdk::SdkConfig;
|
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
|
// 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
|
// 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.project_name, "test-robot");
|
||||||
assert_eq!(config.ftc_sdk_path, sdk_path);
|
assert_eq!(config.ftc_sdk_path, sdk_path);
|
||||||
assert_eq!(config.android_sdk_path, android_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
|
// Save and reload
|
||||||
let project_path = temp_dir.path().join("project");
|
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();
|
let content = fs::read_to_string(project_path.join(".weevil.toml")).unwrap();
|
||||||
|
|
||||||
assert!(content.contains("project_name = \"my-robot\""));
|
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_path"));
|
||||||
assert!(content.contains("ftc_sdk_version"));
|
assert!(content.contains("ftc_sdk_version"));
|
||||||
assert!(content.contains("android_sdk_path"));
|
assert!(content.contains("android_sdk_path"));
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ use std::path::PathBuf;
|
|||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
#[path = "../common.rs"]
|
||||||
|
mod common;
|
||||||
|
use common::EXPECTED_VERSION;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_config_create_and_save() {
|
fn test_config_create_and_save() {
|
||||||
let temp_dir = TempDir::new().unwrap();
|
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.project_name, "test-robot");
|
||||||
assert_eq!(config.ftc_sdk_path, sdk_path);
|
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
|
// Save and reload
|
||||||
config.save(temp_dir.path()).unwrap();
|
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();
|
let content = fs::read_to_string(temp_dir.path().join(".weevil.toml")).unwrap();
|
||||||
|
|
||||||
assert!(content.contains("project_name = \"my-robot\""));
|
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_path"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user