From 6d4001be3d963e4b94b8e1812eb70c68d9c83fe5 Mon Sep 17 00:00:00 2001 From: Pedro Mendes Date: Thu, 27 Apr 2023 11:29:44 -0300 Subject: [PATCH 1/3] feat: New configuration pre-commit Possibility to make a command to check code quality and commit message --- commit.json | 44 +++++++++++++++++++++++ pre-commit.sh | 17 +++++++++ src/commit.rs | 18 ++++++++++ src/commit_message/message_build/tests.rs | 2 ++ src/config/mod.rs | 1 + src/config/tests.rs | 4 +++ src/main.rs | 9 +++-- 7 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 commit.json create mode 100755 pre-commit.sh diff --git a/commit.json b/commit.json new file mode 100644 index 0000000..ddb59ca --- /dev/null +++ b/commit.json @@ -0,0 +1,44 @@ +{ + "config": { + "subject_separator": ": ", + "scope_prefix": "(", + "scope_suffix": ")", + "pre_commit": "./pre-commit.sh" + }, + "commit_types": [ + { "name": "feat", "description": "A new feature" }, + { "name": "fix", "description": "A bug fix" }, + { "name": "docs", "description": "Documentation only changes" }, + { + "name": "style", + "description": "Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)" + }, + { + "name": "refactor", + "description": "A code change that neither fixes a bug nor adds a feature" + }, + { + "name": "perf", + "description": "A code change that improves performance" + }, + { + "name": "test", + "description": "Adding missing tests or correcting existing tests" + }, + { + "name": "chore", + "description": "Other changes that don't modify src or test files" + } + ], + "commit_scopes": [ + { "name": "custom", "description": "Custom scope" }, + { "name": "none", "description": "No scope" } + ], + "msg": { + "commit_type": "What type of commit you will made?", + "commit_scope": "What scope of commit you will made? (Optional)", + "commit_description": "Write a SHORT, IMPERATIVE tense description of the change:", + "commit_body": "Provide a LONGER description of the change (Optional):", + "commit_footer": "List any ISSUES CLOSED by this change E.g.: #31, #34 (Optional):" + } +} diff --git a/pre-commit.sh b/pre-commit.sh new file mode 100755 index 0000000..f7522fb --- /dev/null +++ b/pre-commit.sh @@ -0,0 +1,17 @@ +#!/bin/env bash + +YELLOW='\e[1;33m' +NC='\e[0m' + +if ! cargo fmt -- --check; then + printf "%bHelp: run 'cargo fmt' to fix formatting issues%b" "$YELLOW" "$NC" + exit 1 +fi +if ! cargo clippy --all-targets --all-features -- -D warnings; then + printf "%bHelp: run 'cargo clippy' and fix the issues%b" "$YELLOW" "$NC" + exit 1 +fi +if ! cargo test; then + printf "%bHelp: run 'cargo test' and fix the issues%b" "$YELLOW" "$NC" + exit 1 +fi diff --git a/src/commit.rs b/src/commit.rs index dc9a9ce..d057c15 100644 --- a/src/commit.rs +++ b/src/commit.rs @@ -57,3 +57,21 @@ pub fn write_cached_commit(commit_message: &str) -> Result<()> { fs::write(get_git_path()?.join("COMMIT_EDITMSG"), commit_message)?; Ok(()) } + +pub fn pre_commit_check(pre_commit_command: Option, message: &str) -> Result<()> { + if let Some(command) = pre_commit_command { + println!("Running pre-commit command..."); + let output = Command::new(command).env("MSG", message).output()?; + let message = String::from_utf8_lossy(&output.stdout); + println!("{message}"); + if !output.status.success() { + let error_message = String::from_utf8_lossy(&output.stderr); + return Err(anyhow!( + "Pre-commit command failed with code: {}\n{}", + output.status.code().unwrap_or_default(), + error_message + )); + } + } + Ok(()) +} diff --git a/src/commit_message/message_build/tests.rs b/src/commit_message/message_build/tests.rs index fd1e43d..df731b9 100644 --- a/src/commit_message/message_build/tests.rs +++ b/src/commit_message/message_build/tests.rs @@ -19,6 +19,7 @@ fn message_builder_config_test() { subject_separator: ": ".to_owned(), type_prefix: None, type_suffix: None, + pre_commit: None, }; assert_eq!( @@ -57,6 +58,7 @@ fn message_builder_test() { subject_separator: ": ".to_owned(), type_prefix: None, type_suffix: None, + pre_commit: None, }; let mut builder = MessageBuilder::new(config); diff --git a/src/config/mod.rs b/src/config/mod.rs index 4dfe80b..07ae18d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,6 +17,7 @@ pub struct Config { pub subject_separator: String, pub scope_prefix: String, pub scope_suffix: String, + pub pre_commit: Option, } impl Display for Type { diff --git a/src/config/tests.rs b/src/config/tests.rs index c512a24..4cf4fba 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -1,3 +1,5 @@ +use std::env::set_current_dir; + use super::*; use assert_fs::prelude::*; @@ -11,6 +13,7 @@ fn select_custom_config_path_test() -> Result<()> { let selected_config_path = select_custom_config_path(config_path.clone())?; assert_eq!(config_path.unwrap().to_str(), selected_config_path.to_str()); + set_current_dir(temp_dir.path())?; let config_path_default = dirs::config_dir().unwrap().join("commit/commit.json"); let selected_config_path = select_custom_config_path(None)?; assert_eq!(selected_config_path.to_str(), config_path_default.to_str()); @@ -25,6 +28,7 @@ fn select_custom_config_path_test() -> Result<()> { #[test] fn get_config_path_test() -> Result<()> { + set_current_dir("/tmp")?; let config_file = dirs::config_dir() .ok_or_else(|| anyhow!("Could not find config directory"))? .join("commit/commit.json"); diff --git a/src/main.rs b/src/main.rs index 7a6b8f3..e7ff637 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,9 @@ use clap::Parser; use std::io::Write; use std::path::PathBuf; -use commit::{check_staged_files, commit, read_cached_commit, write_cached_commit}; +use commit::{ + check_staged_files, commit, pre_commit_check, read_cached_commit, write_cached_commit, +}; use commit_message::make_message_commit; const DEFAULT_CONFIG_FILE: &str = include_str!("../commit-default.json"); @@ -56,9 +58,12 @@ fn main() -> Result<()> { } let pattern = config::get_pattern(args.config)?; - let commit_message = make_message_commit(pattern)?; + + let commit_message = make_message_commit(pattern.clone())?; write_cached_commit(&commit_message)?; + pre_commit_check(pattern.config.pre_commit, &commit_message)?; + if args.hook { return Ok(()); } From b679e4025364c655a5aa30019139d9d6a69f125e Mon Sep 17 00:00:00 2001 From: Pedro Mendes Date: Thu, 27 Apr 2023 11:40:54 -0300 Subject: [PATCH 2/3] fix: Fix test on windows using temp dir instead /tmp --- src/config/tests.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/config/tests.rs b/src/config/tests.rs index 4cf4fba..c7ea6b6 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -23,17 +23,20 @@ fn select_custom_config_path_test() -> Result<()> { Err(err) => assert_eq!(err.to_string(), "Config file does not exist: "), _ => unreachable!(), } + temp_dir.close()?; Ok(()) } #[test] fn get_config_path_test() -> Result<()> { - set_current_dir("/tmp")?; + let temp_dir = assert_fs::TempDir::new()?; + set_current_dir(temp_dir.path())?; let config_file = dirs::config_dir() .ok_or_else(|| anyhow!("Could not find config directory"))? .join("commit/commit.json"); let config_path = get_config_path(); assert_eq!(config_file.to_str(), config_path?.to_str()); + temp_dir.close()?; Ok(()) } @@ -50,16 +53,20 @@ fn get_config_path_content_test() -> Result<()> { config_file.write_str(expected)?; let content = get_config_path_content(config_path)?; assert_eq!(content, expected); + temp_dir.close()?; Ok(()) } #[test] fn get_pattern_test() -> Result<()> { + let temp_dir = assert_fs::TempDir::new()?; + set_current_dir(temp_dir.path())?; let pattern = get_pattern(None)?; assert_eq!(pattern.config.type_prefix, None); assert_eq!(pattern.config.type_suffix, None); assert_eq!(pattern.config.subject_separator, ": "); assert_eq!(pattern.config.scope_prefix, "("); assert_eq!(pattern.config.scope_suffix, ")"); + temp_dir.close()?; Ok(()) } From f1babf0c8b79b86be563603e5e6454ddebf61d61 Mon Sep 17 00:00:00 2001 From: Pedro Mendes Date: Thu, 27 Apr 2023 12:06:40 -0300 Subject: [PATCH 3/3] fix: Go back to the initial dir to don't fail on windows being used by another process --- src/config/tests.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/config/tests.rs b/src/config/tests.rs index c7ea6b6..a317210 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -1,4 +1,4 @@ -use std::env::set_current_dir; +use std::env::{current_dir, set_current_dir}; use super::*; use assert_fs::prelude::*; @@ -13,6 +13,7 @@ fn select_custom_config_path_test() -> Result<()> { let selected_config_path = select_custom_config_path(config_path.clone())?; assert_eq!(config_path.unwrap().to_str(), selected_config_path.to_str()); + let last_dir = current_dir()?; set_current_dir(temp_dir.path())?; let config_path_default = dirs::config_dir().unwrap().join("commit/commit.json"); let selected_config_path = select_custom_config_path(None)?; @@ -23,6 +24,7 @@ fn select_custom_config_path_test() -> Result<()> { Err(err) => assert_eq!(err.to_string(), "Config file does not exist: "), _ => unreachable!(), } + set_current_dir(last_dir)?; temp_dir.close()?; Ok(()) } @@ -30,12 +32,14 @@ fn select_custom_config_path_test() -> Result<()> { #[test] fn get_config_path_test() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; + let last_dir = current_dir()?; set_current_dir(temp_dir.path())?; let config_file = dirs::config_dir() .ok_or_else(|| anyhow!("Could not find config directory"))? .join("commit/commit.json"); let config_path = get_config_path(); assert_eq!(config_file.to_str(), config_path?.to_str()); + set_current_dir(last_dir)?; temp_dir.close()?; Ok(()) } @@ -60,6 +64,7 @@ fn get_config_path_content_test() -> Result<()> { #[test] fn get_pattern_test() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; + let last_dir = current_dir()?; set_current_dir(temp_dir.path())?; let pattern = get_pattern(None)?; assert_eq!(pattern.config.type_prefix, None); @@ -67,6 +72,7 @@ fn get_pattern_test() -> Result<()> { assert_eq!(pattern.config.subject_separator, ": "); assert_eq!(pattern.config.scope_prefix, "("); assert_eq!(pattern.config.scope_suffix, ")"); + set_current_dir(last_dir)?; temp_dir.close()?; Ok(()) }