Compare commits

..

No commits in common. "e7df35a765185a61a57c04c0cd71dbe59c4e860b" and "260bcb7ca5acb4561c86b48f5798e6e1a026f30a" have entirely different histories.

14 changed files with 474 additions and 768 deletions

996
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -19,22 +19,21 @@ workspace = true
[dependencies] [dependencies]
color-eyre = "0.6.2" color-eyre = "0.6.2"
globset = "0.4.14" globset = "0.4.9"
lazy_static = "1.4.0" owo-colors = "3.5.0"
owo-colors = "4.0.0"
subprocess = "0.2.9" subprocess = "0.2.9"
supports-color = "2.1.0" supports-color = "1.3.0"
tera = "1.19.1" tera = "1.17.1"
[dependencies.clap] [dependencies.clap]
features = ["derive"] features = ["derive"]
version = "4.4.18" version = "4.0.18"
[dependencies.hooked-config] [dependencies.hooked-config]
path = "../hooked-config" path = "../hooked-config"
version = "0.1.0" version = "0.1.0"
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.13" assert_cmd = "2.0.5"
insta = "1.34.0" insta = "1.21.0"
test-case = "3.3.1" test-case = "2.2.2"

View File

@ -2,10 +2,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use { use clap::{Args as Arguments, Parser, Subcommand};
clap::{Args as Arguments, Parser, Subcommand},
hooked_config::NoiseLevel,
};
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
mod cli_reference; mod cli_reference;
@ -72,10 +69,6 @@ pub struct RunArgs {
/// The hook type to run. /// The hook type to run.
#[clap(value_parser = crate::HOOK_TYPES)] #[clap(value_parser = crate::HOOK_TYPES)]
pub hook_type: String, pub hook_type: String,
/// The noise level to override for all hooks.
#[clap(long)]
pub noise_level: Option<NoiseLevel>,
} }
/// The `cli-reference` subcommand arguments. /// The `cli-reference` subcommand arguments.

View File

@ -5,31 +5,34 @@ use std::{io::Read, process::exit};
use { use {
color_eyre::{eyre::eyre, Result}, color_eyre::{eyre::eyre, Result},
hooked_config::{Config, ExitAction}, hooked_config::{Config, ExitAction},
owo_colors::OwoColorize, owo_colors::{OwoColorize, Style},
subprocess::{Exec, Redirection}, subprocess::{Exec, Redirection},
supports_color::Stream,
}; };
use crate::{ use crate::utilities::{globset_from_strings, plural};
cli::RunArgs,
printer::{print, PrintType, PRINT_STYLE},
utilities::{globset_from_strings, plural},
};
/// The `run` subcommand. /// The `run` subcommand.
pub fn hooked_run(config: Config, args: RunArgs) -> Result<()> { pub fn hooked_run(config: Config, hook_type: String) -> Result<()> {
let cli_noise_level = args.noise_level.as_ref(); let (success_style, warn_style, error_style, skipped_style) =
let global_noise_level = &config.general.noise_level; if let Some(_support) = supports_color::on(Stream::Stdout) {
let shared_style = Style::new().bold();
(
shared_style.green(),
shared_style.yellow(),
shared_style.red(),
shared_style.blue(),
)
} else {
(Style::new(), Style::new(), Style::new(), Style::new())
};
if args.hook_type == "pre-commit" { if hook_type == "pre-commit" {
let hook_count = config.pre_commit.len(); let hook_count = config.pre_commit.len();
print( println!(
format!(
"Hooked: Running {} pre-commit {}.", "Hooked: Running {} pre-commit {}.",
hook_count, hook_count,
plural(hook_count, "hook", None) plural(hook_count, "hook", None)
),
cli_noise_level.unwrap_or(global_noise_level),
PrintType::Info,
); );
'hook_loop: for hook in config.pre_commit { 'hook_loop: for hook in config.pre_commit {
@ -43,14 +46,10 @@ pub fn hooked_run(config: Config, args: RunArgs) -> Result<()> {
.capture()? .capture()?
.stdout_str(); .stdout_str();
if !staged_files.lines().any(|line| globs.is_match(line)) { if !staged_files.lines().any(|line| globs.is_match(line)) {
print( println!(
format!(
"\t{} {}", "\t{} {}",
"".style(PRINT_STYLE.skipped), "".style(skipped_style),
hook_name.style(PRINT_STYLE.skipped) hook_name.style(skipped_style)
),
cli_noise_level.unwrap_or(global_noise_level),
PrintType::Info,
); );
continue 'hook_loop; continue 'hook_loop;
} }
@ -85,32 +84,16 @@ pub fn hooked_run(config: Config, args: RunArgs) -> Result<()> {
output output
}; };
let (stop, print_output, prefix, style, print_type) = let (stop, print_output, prefix, style) =
match (exit_status.success(), hook.on_failure) { match (exit_status.success(), hook.on_failure) {
(true, _) => { (true, _) => (false, false, "", success_style),
(false, false, "", PRINT_STYLE.success, PrintType::Info) (false, ExitAction::Continue) => (false, true, "", warn_style),
} (false, ExitAction::Stop) => (true, true, "", error_style),
(false, ExitAction::Continue) => {
(false, true, "", PRINT_STYLE.warn, PrintType::Warn)
}
(false, ExitAction::Stop) => {
(true, true, "", PRINT_STYLE.error, PrintType::Error)
}
}; };
let hook_noise_level = println!("\t{} {}", prefix.style(style), hook_name.style(style));
hook.noise_level.as_ref().unwrap_or(global_noise_level);
print(
format!("\t{} {}", prefix.style(style), hook_name.style(style)),
cli_noise_level.unwrap_or(hook_noise_level),
print_type,
);
if !output.is_empty() && print_output { if !output.is_empty() && print_output {
print( println!("{}", output);
output,
cli_noise_level.unwrap_or(hook_noise_level),
PrintType::Info,
);
} }
if stop { if stop {

View File

@ -17,7 +17,6 @@ pub const DEFAULT_TEMPLATE: &str = include_str!("templates/default.sh");
pub const HOOK_TYPES: [&str; 1] = ["pre-commit"]; pub const HOOK_TYPES: [&str; 1] = ["pre-commit"];
mod cli; mod cli;
mod printer;
mod utilities; mod utilities;
fn main() -> Result<()> { fn main() -> Result<()> {
@ -36,7 +35,7 @@ fn main() -> Result<()> {
} }
MainSubcommands::Run(sub_args) => { MainSubcommands::Run(sub_args) => {
cli::hooked_run(config, sub_args)?; cli::hooked_run(config, sub_args.hook_type)?;
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]

View File

@ -1,76 +0,0 @@
//! Shared logic for printing output to the terminal.
use {
hooked_config::NoiseLevel, lazy_static::lazy_static, owo_colors::Style,
std::fmt::Display, supports_color::Stream,
};
/// The available types to print output as.
#[derive(Debug, Eq, PartialEq)]
pub enum PrintType {
/// Print the output as an error line.
Error,
/// Print the output as a warning line.
Warn,
/// Print the output as an information line.
Info,
}
/// The available print styles for colorized output.
#[derive(Debug)]
pub struct PrintStyles {
/// The style for errored hooks output.
pub error: Style,
/// The style for skipped hooks output.
pub skipped: Style,
/// The style for succesful hooks output.
pub success: Style,
/// The style for hooks with warnings.
pub warn: Style,
}
lazy_static! {
pub static ref PRINT_STYLE: PrintStyles = {
let (success_style, warn_style, error_style, skipped_style) =
if let Some(_support) = supports_color::on(Stream::Stdout) {
let shared_style = Style::new().bold();
(
shared_style.green(),
shared_style.yellow(),
shared_style.red(),
shared_style.blue(),
)
} else {
(Style::new(), Style::new(), Style::new(), Style::new())
};
PrintStyles {
error: error_style,
skipped: skipped_style,
success: success_style,
warn: warn_style,
}
};
}
/// Print something to the terminal according to a given [`NoiseLevel`] and
/// [`PrintType`].
pub fn print<D: Display>(
something: D,
noise_level: &NoiseLevel,
print_type: PrintType,
) {
let should_print = match (noise_level, print_type) {
// Only output errors under the quiet noise level.
(NoiseLevel::Quiet, PrintType::Error) => true,
(NoiseLevel::Quiet, _) => false,
// Output everything under loud.
(NoiseLevel::Loud | NoiseLevel::Standard | NoiseLevel::Minimal, _) => true,
};
if !should_print {
return;
}
println!("{something}")
}

View File

@ -18,12 +18,12 @@ workspace = true
[dependencies] [dependencies]
color-eyre = "0.6.2" color-eyre = "0.6.2"
toml = "0.8.8" toml = "0.5.9"
[dependencies.serde] [dependencies.serde]
features = ["derive"] features = ["derive"]
version = "1.0.195" version = "1.0.147"
[dev-dependencies] [dev-dependencies]
insta = "1.34.0" insta = "1.21.0"
test-case = "3.3.1" test-case = "2.2.2"

View File

@ -3,7 +3,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// The noise level Hooked should output logs with. /// The noise level Hooked should output logs with.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum NoiseLevel { pub enum NoiseLevel {
/// Output only errors. /// Output only errors.
@ -22,16 +22,3 @@ impl Default for NoiseLevel {
Self::Standard Self::Standard
} }
} }
// Implement `From<String>` so we can use Clap's automatic parsing in the CLI.
impl From<String> for NoiseLevel {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"quiet" => Self::Quiet,
"loud" => Self::Loud,
"standard" => Self::Standard,
"minimal" => Self::Minimal,
_ => NoiseLevel::default(),
}
}
}

View File

@ -12,7 +12,8 @@ pub struct PreCommit {
pub name: Option<String>, pub name: Option<String>,
/// The noise level this task should output with. /// The noise level this task should output with.
pub noise_level: Option<NoiseLevel>, #[serde(default)]
pub noise_level: NoiseLevel,
/// What to do when the hook exits with a non-zero status code. /// What to do when the hook exits with a non-zero status code.
#[serde(default)] #[serde(default)]

View File

@ -5,6 +5,7 @@ template = "test.sh"
[[pre_commit]] [[pre_commit]]
name = "Pre Commit 1" name = "Pre Commit 1"
noise_level = "quiet"
command = "exit 0" command = "exit 0"
staged = ["*.txt"] staged = ["*.txt"]
on_failure = "continue" on_failure = "continue"

View File

@ -9,7 +9,7 @@ use insta::assert_snapshot;
fn test_serialize() { fn test_serialize() {
let pre_commit_command = PreCommit { let pre_commit_command = PreCommit {
name: Some("Command Test".to_string()), name: Some("Command Test".to_string()),
noise_level: None, noise_level: NoiseLevel::Quiet,
on_failure: ExitAction::Continue, on_failure: ExitAction::Continue,
staged: vec!["*.txt".to_string()], staged: vec!["*.txt".to_string()],
task: Task { task: Task {
@ -20,7 +20,7 @@ fn test_serialize() {
let pre_commit_script = PreCommit { let pre_commit_script = PreCommit {
name: Some("Script Test".to_string()), name: Some("Script Test".to_string()),
noise_level: Some(NoiseLevel::Loud), noise_level: NoiseLevel::Loud,
on_failure: ExitAction::Stop, on_failure: ExitAction::Stop,
staged: vec![], staged: vec![],
task: Task { task: Task {

View File

@ -12,7 +12,7 @@ Config {
pre_commit: [ pre_commit: [
PreCommit { PreCommit {
name: None, name: None,
noise_level: None, noise_level: Standard,
on_failure: Stop, on_failure: Stop,
staged: [], staged: [],
task: Task { task: Task {

View File

@ -16,7 +16,7 @@ Config {
name: Some( name: Some(
"Pre Commit 1", "Pre Commit 1",
), ),
noise_level: None, noise_level: Quiet,
on_failure: Continue, on_failure: Continue,
staged: [ staged: [
"*.txt", "*.txt",
@ -32,9 +32,7 @@ Config {
name: Some( name: Some(
"Pre Commit 2", "Pre Commit 2",
), ),
noise_level: Some( noise_level: Loud,
Loud,
),
on_failure: Stop, on_failure: Stop,
staged: [], staged: [],
task: Task { task: Task {

View File

@ -3,20 +3,21 @@ source: hooked-config/tests/serialize.rs
expression: to_string_pretty(&config).unwrap() expression: to_string_pretty(&config).unwrap()
--- ---
[general] [general]
config = "Hooked.toml" config = 'Hooked.toml'
directory = "hooks" directory = 'hooks'
noise_level = "standard" noise_level = 'standard'
[[pre_commit]] [[pre_commit]]
name = "Command Test" name = 'Command Test'
on_failure = "continue" noise_level = 'quiet'
staged = ["*.txt"] on_failure = 'continue'
command = "exit 0" staged = ['*.txt']
command = 'exit 0'
[[pre_commit]] [[pre_commit]]
name = "Script Test" name = 'Script Test'
noise_level = "loud" noise_level = 'loud'
on_failure = "stop" on_failure = 'stop'
staged = [] staged = []
script = "test.sh" script = 'test.sh'