From 9c0b2a50be310e22101f51322889add48f79fefa Mon Sep 17 00:00:00 2001 From: Audrow Nash Date: Sat, 17 Feb 2024 22:16:19 -0600 Subject: [PATCH] Refactor + add init config --- Cargo.lock | 48 ++++++ src/yatm_v2/Cargo.toml | 1 + src/yatm_v2/src/{utils => app}/cli.rs | 7 +- src/yatm_v2/src/app/init_config.rs | 159 ++++++++++++++++++ src/yatm_v2/src/app/mod.rs | 4 + .../get_local_issues_without_matches.rs} | 7 +- .../{utils/github.rs => github/github_api.rs} | 0 src/yatm_v2/src/github/mod.rs | 5 + src/yatm_v2/src/main.rs | 17 +- .../{utils => test_cases}/make_test_cases.rs | 0 src/yatm_v2/src/test_cases/mod.rs | 5 + .../test_case_to_markdown.rs} | 5 +- src/yatm_v2/src/{utils => types}/config.rs | 5 +- .../src/{utils => types}/local_issue.rs | 0 src/yatm_v2/src/types/mod.rs | 5 + src/yatm_v2/src/utils/mod.rs | 7 - 16 files changed, 250 insertions(+), 25 deletions(-) rename src/yatm_v2/src/{utils => app}/cli.rs (95%) create mode 100644 src/yatm_v2/src/app/init_config.rs create mode 100644 src/yatm_v2/src/app/mod.rs rename src/yatm_v2/src/{utils/github_utils.rs => github/get_local_issues_without_matches.rs} (98%) rename src/yatm_v2/src/{utils/github.rs => github/github_api.rs} (100%) create mode 100644 src/yatm_v2/src/github/mod.rs rename src/yatm_v2/src/{utils => test_cases}/make_test_cases.rs (100%) create mode 100644 src/yatm_v2/src/test_cases/mod.rs rename src/yatm_v2/src/{utils/template.rs => test_cases/test_case_to_markdown.rs} (89%) rename src/yatm_v2/src/{utils => types}/config.rs (70%) rename src/yatm_v2/src/{utils => types}/local_issue.rs (100%) create mode 100644 src/yatm_v2/src/types/mod.rs delete mode 100644 src/yatm_v2/src/utils/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 1500ebf..1da0980 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -352,6 +352,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "fnv" version = "1.0.7" @@ -697,6 +713,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "lock_api" version = "0.4.11" @@ -999,6 +1021,19 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "rustls" version = "0.21.10" @@ -1274,6 +1309,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "thiserror" version = "1.0.56" @@ -1783,6 +1830,7 @@ dependencies = [ "percent-encoding", "serde", "serde_yaml", + "tempfile", "tokio", "url", ] diff --git a/src/yatm_v2/Cargo.toml b/src/yatm_v2/Cargo.toml index 35b2340..4af7526 100644 --- a/src/yatm_v2/Cargo.toml +++ b/src/yatm_v2/Cargo.toml @@ -19,5 +19,6 @@ octocrab = "0.33.4" percent-encoding = "2.3.1" serde = { version = "1.0.196", features = ["derive"] } serde_yaml = "0.9.31" +tempfile = "3.10.0" tokio = { version = "1.36.0", features = ["full"] } url = "2.5.0" diff --git a/src/yatm_v2/src/utils/cli.rs b/src/yatm_v2/src/app/cli.rs similarity index 95% rename from src/yatm_v2/src/utils/cli.rs rename to src/yatm_v2/src/app/cli.rs index fe4204d..8cf317b 100644 --- a/src/yatm_v2/src/utils/cli.rs +++ b/src/yatm_v2/src/app/cli.rs @@ -1,5 +1,7 @@ +use crate::app::init_config::init_config; use std::path::PathBuf; +use anyhow::Result; use clap::{Parser, Subcommand}; // Define the main application @@ -72,12 +74,12 @@ enum GithubSubcommands { Preview, } -pub fn cli() { +pub fn cli() -> Result<()> { let cli = MyApp::parse(); match cli.command { Commands::Init { path } => { - println!("Creating a new project at {:?}", path); + init_config(&path)?; } Commands::Requirements { subcommand } => match subcommand { RequirementsSubcommands::Validate(options) => { @@ -110,4 +112,5 @@ pub fn cli() { } }, } + Ok(()) } diff --git a/src/yatm_v2/src/app/init_config.rs b/src/yatm_v2/src/app/init_config.rs new file mode 100644 index 0000000..3063a43 --- /dev/null +++ b/src/yatm_v2/src/app/init_config.rs @@ -0,0 +1,159 @@ +use crate::types::Config; +use anyhow::{Context, Result}; +use serde_yaml; +use std::{os, path::PathBuf}; + +pub fn init_config(dir: &PathBuf) -> Result<()> { + make_sure_empty_dir_exists(dir)?; + + let config = Config::default(); + let config_file = dir.join("config.yaml"); + std::fs::write( + &config_file, + serde_yaml::to_string(&config).context("Failed to serialize the config")?, + ) + .context("Failed to write the config file")?; + + if config.requirements_dirs.len() == 1 { + let requirements_dir = dir.join(&config.requirements_dirs[0]); + make_sure_empty_dir_exists(&requirements_dir)?; + } + + let generated_files_dir = dir.join(&config.generated_files_dir); + make_sure_empty_dir_exists(&generated_files_dir)?; + + // add a .gitignore file with the generated_files_dir + let gitignore_file = dir.join(".gitignore"); + std::fs::write( + &gitignore_file, + &format!("/{}", config.generated_files_dir.to_string_lossy()), + ) + .context("Failed to write the .gitignore file")?; + + Ok(()) +} + +#[cfg(test)] +mod test_init_config { + use super::init_config; + use std::fs; + use tempfile::tempdir; + + #[test] + fn init_config_creates_files() { + let dir = tempdir().unwrap().path().to_path_buf(); + init_config(&dir).unwrap(); + assert!(dir.join("config.yaml").is_file()); + assert!(dir.join("requirements").is_dir()); + assert!(dir.join(".generated_files").is_dir()); + assert!(dir.join(".gitignore").is_file()); + } + + #[test] + fn init_config_exists_not_empty() { + let dir = tempdir().unwrap().path().to_path_buf(); + fs::create_dir(&dir).unwrap(); + fs::File::create(dir.join("file")).unwrap(); + assert!(init_config(&dir).is_err()); + } + + #[test] + fn init_config_exists_file() { + let dir = tempdir().unwrap().path().to_path_buf(); + fs::File::create(&dir).unwrap(); + assert!(init_config(&dir).is_err()); + } +} + +fn make_sure_empty_dir_exists(dir: &PathBuf) -> Result<()> { + if dir.is_file() { + anyhow::bail!(format!("Path already exists and is a file: {:?}", dir)); + } + if dir.is_dir() { + if !is_empty_directory(dir)? { + anyhow::bail!(format!("Directory is not empty: {:?}", dir)); + } + } else { + std::fs::create_dir(dir).context("Failed to create the directory")?; + } + Ok(()) +} + +#[cfg(test)] +mod test_make_sure_empty_dir_exists { + use super::is_empty_directory; + use super::make_sure_empty_dir_exists; + use std::fs; + use tempfile::tempdir; + + #[test] + fn create_empty_dir() { + let dir = tempdir().unwrap().path().to_path_buf(); + make_sure_empty_dir_exists(&dir).unwrap(); + assert!(dir.is_dir()); + assert!(is_empty_directory(&dir).unwrap()); + } + + #[test] + fn create_empty_dir_exists() { + let dir = tempdir().unwrap().path().to_path_buf(); + fs::create_dir(&dir).unwrap(); + make_sure_empty_dir_exists(&dir).unwrap(); + assert!(dir.is_dir()); + assert!(is_empty_directory(&dir).unwrap()); + } + + #[test] + fn create_empty_dir_exists_not_empty() { + let dir = tempdir().unwrap().path().to_path_buf(); + fs::create_dir(&dir).unwrap(); + fs::File::create(dir.join("file")).unwrap(); + assert!(make_sure_empty_dir_exists(&dir).is_err()); + } + + #[test] + fn create_empty_dir_exists_file() { + let dir = tempdir().unwrap().path().to_path_buf(); + fs::File::create(&dir).unwrap(); + assert!(make_sure_empty_dir_exists(&dir).is_err()); + } +} + +fn is_empty_directory(dir: &PathBuf) -> Result { + if dir.is_dir() { + let mut entries = std::fs::read_dir(dir).context("Failed to read the directory")?; + if entries.next().is_none() { + return Ok(true); + } + } + Ok(false) +} + +#[cfg(test)] +mod test_is_empty_directory { + use super::is_empty_directory; + use std::fs; + use std::path::PathBuf; + use tempfile::tempdir; + + #[test] + fn is_empty() { + let dir = tempdir().unwrap().path().to_path_buf(); + fs::create_dir(&dir).unwrap(); + assert!(is_empty_directory(&dir).unwrap()); + } + + #[test] + fn is_not_empty() { + let dir = tempdir().unwrap().path().to_path_buf(); + fs::create_dir(&dir).unwrap(); + fs::File::create(dir.join("file")).unwrap(); + assert!(!is_empty_directory(&dir).unwrap()); + } + + #[test] + fn is_not_exists() { + let dir = tempdir().unwrap().path().to_path_buf(); + assert!(!is_empty_directory(&dir).unwrap()); + } +} diff --git a/src/yatm_v2/src/app/mod.rs b/src/yatm_v2/src/app/mod.rs new file mode 100644 index 0000000..8022080 --- /dev/null +++ b/src/yatm_v2/src/app/mod.rs @@ -0,0 +1,4 @@ +mod cli; +mod init_config; + +pub use cli::cli; diff --git a/src/yatm_v2/src/utils/github_utils.rs b/src/yatm_v2/src/github/get_local_issues_without_matches.rs similarity index 98% rename from src/yatm_v2/src/utils/github_utils.rs rename to src/yatm_v2/src/github/get_local_issues_without_matches.rs index 0e072be..5fd52ef 100644 --- a/src/yatm_v2/src/utils/github_utils.rs +++ b/src/yatm_v2/src/github/get_local_issues_without_matches.rs @@ -1,4 +1,4 @@ -use crate::utils::local_issue::LocalIssue; +use crate::types::LocalIssue; use octocrab::models::issues::Issue as GithubIssue; struct GithubIssueHelper { @@ -136,10 +136,7 @@ mod test_get_local_issues_without_matches { } } -pub fn is_local_issue_match_github_issue( - local_issue: &LocalIssue, - github_issue: &GithubIssue, -) -> bool { +fn is_local_issue_match_github_issue(local_issue: &LocalIssue, github_issue: &GithubIssue) -> bool { let github_issue_helper = GithubIssueHelper { title: github_issue.title.clone(), labels: github_issue diff --git a/src/yatm_v2/src/utils/github.rs b/src/yatm_v2/src/github/github_api.rs similarity index 100% rename from src/yatm_v2/src/utils/github.rs rename to src/yatm_v2/src/github/github_api.rs diff --git a/src/yatm_v2/src/github/mod.rs b/src/yatm_v2/src/github/mod.rs new file mode 100644 index 0000000..121fce2 --- /dev/null +++ b/src/yatm_v2/src/github/mod.rs @@ -0,0 +1,5 @@ +mod get_local_issues_without_matches; +mod github_api; + +pub use get_local_issues_without_matches::get_local_issues_without_matches; +pub use github_api::Github; diff --git a/src/yatm_v2/src/main.rs b/src/yatm_v2/src/main.rs index 148d5e3..bdecd1c 100644 --- a/src/yatm_v2/src/main.rs +++ b/src/yatm_v2/src/main.rs @@ -1,11 +1,14 @@ -mod utils; +mod app; +mod github; +mod test_cases; +mod types; + use anyhow::{Context, Ok, Result}; -use utils::local_issue; +use types::LocalIssue; -use crate::utils::github::Github; -use crate::utils::github_utils::get_local_issues_without_matches; -use crate::utils::local_issue::LocalIssue; -use crate::utils::template::get_github_issue_content; +use crate::github::get_local_issues_without_matches; +use crate::github::Github; +use crate::test_cases::test_case_to_markdown; use chrono; use common::types::TestCase; @@ -94,7 +97,7 @@ fn demo_template() { selected_permutation, }; - let result = get_github_issue_content(test_case).unwrap(); + let result = test_case_to_markdown(test_case).unwrap(); println!("{}", result.title); println!("{}", result.text_body); println!("{:?}", result.labels); diff --git a/src/yatm_v2/src/utils/make_test_cases.rs b/src/yatm_v2/src/test_cases/make_test_cases.rs similarity index 100% rename from src/yatm_v2/src/utils/make_test_cases.rs rename to src/yatm_v2/src/test_cases/make_test_cases.rs diff --git a/src/yatm_v2/src/test_cases/mod.rs b/src/yatm_v2/src/test_cases/mod.rs new file mode 100644 index 0000000..db07409 --- /dev/null +++ b/src/yatm_v2/src/test_cases/mod.rs @@ -0,0 +1,5 @@ +mod make_test_cases; +mod test_case_to_markdown; + +pub use make_test_cases::make_test_cases; +pub use test_case_to_markdown::test_case_to_markdown; diff --git a/src/yatm_v2/src/utils/template.rs b/src/yatm_v2/src/test_cases/test_case_to_markdown.rs similarity index 89% rename from src/yatm_v2/src/utils/template.rs rename to src/yatm_v2/src/test_cases/test_case_to_markdown.rs index 6c4b49c..b4d78ac 100644 --- a/src/yatm_v2/src/utils/template.rs +++ b/src/yatm_v2/src/test_cases/test_case_to_markdown.rs @@ -1,8 +1,7 @@ -use crate::utils::local_issue::LocalIssue; +use crate::types::LocalIssue; use anyhow::{Context, Result}; use askama::Template; use common::types::{Action, Expect, Link, Step, TestCase}; -use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Template, Clone)] @@ -14,7 +13,7 @@ struct GithubIssueTemplate { selected_permutation: HashMap, } -pub fn get_github_issue_content(test_case: TestCase) -> Result { +pub fn test_case_to_markdown(test_case: TestCase) -> Result { let labels = get_labels(&test_case); let template = GithubIssueTemplate { diff --git a/src/yatm_v2/src/utils/config.rs b/src/yatm_v2/src/types/config.rs similarity index 70% rename from src/yatm_v2/src/utils/config.rs rename to src/yatm_v2/src/types/config.rs index 5d48888..b0b0e0a 100644 --- a/src/yatm_v2/src/utils/config.rs +++ b/src/yatm_v2/src/types/config.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Config { + pub yatm_v2_version: String, pub repo_name: String, pub repo_owner: String, pub requirements_dirs: Vec, @@ -11,11 +12,13 @@ pub struct Config { impl Config { pub fn default() -> Self { + const VERSION: &str = env!("CARGO_PKG_VERSION"); Config { + yatm_v2_version: VERSION.to_string(), repo_name: "repo_name".to_string(), repo_owner: "repo_owner".to_string(), requirements_dirs: vec![PathBuf::new().join("requirements")], - generated_files_dir: PathBuf::new(), + generated_files_dir: PathBuf::new().join(".generated_files"), } } } diff --git a/src/yatm_v2/src/utils/local_issue.rs b/src/yatm_v2/src/types/local_issue.rs similarity index 100% rename from src/yatm_v2/src/utils/local_issue.rs rename to src/yatm_v2/src/types/local_issue.rs diff --git a/src/yatm_v2/src/types/mod.rs b/src/yatm_v2/src/types/mod.rs new file mode 100644 index 0000000..cf9389c --- /dev/null +++ b/src/yatm_v2/src/types/mod.rs @@ -0,0 +1,5 @@ +mod config; +mod local_issue; + +pub use config::Config; +pub use local_issue::LocalIssue; diff --git a/src/yatm_v2/src/utils/mod.rs b/src/yatm_v2/src/utils/mod.rs deleted file mode 100644 index cc9c801..0000000 --- a/src/yatm_v2/src/utils/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod cli; -pub mod config; -pub mod github; -pub mod github_utils; -pub mod local_issue; -pub mod make_test_cases; -pub mod template;