Compare commits
37 Commits
Author | SHA1 | Date |
---|---|---|
Bauke | 87c53d5e09 | |
Bauke | dff366f9a0 | |
Bauke | 595b8c25c1 | |
Bauke | caa158ce9f | |
Bauke | b98426a993 | |
Bauke | d12895184b | |
Bauke | 9a4299e5a1 | |
Bauke | 9e7dd2e3dd | |
Bauke | e7df35a765 | |
Bauke | a9ee3c20fe | |
Bauke | 6b6c48c476 | |
Bauke | 0634e86b3d | |
Bauke | f0030fd57f | |
Bauke | df397b2cda | |
Bauke | 260bcb7ca5 | |
Bauke | ba6d4fb0d1 | |
Bauke | d031374360 | |
Bauke | 762051116e | |
Bauke | 15dcca32b0 | |
Bauke | 3da03abe16 | |
Bauke | 6512eaac5a | |
Bauke | 0d09e2e086 | |
Bauke | 47b1b7ec51 | |
Bauke | 5d26a72c8b | |
Bauke | 4a4974fa35 | |
Bauke | e4ed623e64 | |
Bauke | 651699c40a | |
Bauke | da0e38e3bb | |
Bauke | 4ba723d5cc | |
Bauke | a8f587f43a | |
Bauke | 82cbc580dc | |
Bauke | 5bb3a282c3 | |
Bauke | a4d0431a32 | |
Bauke | 8d1baaf57f | |
Bauke | 1a79f9e051 | |
Bauke | 9c11ae3db6 | |
Bauke | aed22fad90 |
|
@ -1,9 +1,7 @@
|
|||
# Generated by Cargo
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Code coverage results
|
||||
.direnv/
|
||||
.vscode/
|
||||
coverage/
|
||||
|
||||
# mdBook output
|
||||
debug/
|
||||
hooked-book/book/
|
||||
outputs/
|
||||
target/
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,3 +3,11 @@ members = [
|
|||
"hooked-cli",
|
||||
"hooked-config"
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
missing_docs_in_private_items = "warn"
|
||||
|
||||
[workspace.lints.rust]
|
||||
missing_docs = "warn"
|
||||
unsafe_code = "forbid"
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
[[pre_commit]]
|
||||
name = "Cargo Complete Check"
|
||||
command = "cargo make complete-check"
|
||||
|
||||
[[pre_commit]]
|
||||
name = "Typos"
|
||||
command = "typos"
|
||||
|
|
|
@ -1,32 +1,18 @@
|
|||
[env]
|
||||
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
||||
|
||||
[tasks.fmt]
|
||||
command = "cargo"
|
||||
args = ["fmt", "${@}"]
|
||||
|
||||
[tasks.check]
|
||||
command = "cargo"
|
||||
args = ["check", "${@}"]
|
||||
|
||||
[tasks.clippy]
|
||||
command = "cargo"
|
||||
args = ["clippy", "${@}"]
|
||||
|
||||
[tasks.test]
|
||||
command = "cargo"
|
||||
args = ["test", "${@}"]
|
||||
|
||||
[tasks.doc]
|
||||
command = "cargo"
|
||||
args = ["doc", "${@}"]
|
||||
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["build", "${@}"]
|
||||
|
||||
[tasks.complete-check]
|
||||
dependencies = ["fmt", "check", "clippy", "test", "doc", "build"]
|
||||
dependencies = [
|
||||
"format",
|
||||
"check",
|
||||
"clippy",
|
||||
"test",
|
||||
"code-coverage",
|
||||
"docs",
|
||||
"build",
|
||||
"audit-flow",
|
||||
"outdated-flow",
|
||||
]
|
||||
|
||||
[tasks.code-coverage]
|
||||
workspace = false
|
||||
|
@ -38,7 +24,7 @@ args = [
|
|||
"--out=html",
|
||||
"--output-dir=coverage",
|
||||
"--skip-clean",
|
||||
"--target-dir=target/tarpaulin"
|
||||
"--target-dir=target/tarpaulin",
|
||||
]
|
||||
|
||||
[tasks.book]
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
> **Git hooks manager.**
|
||||
|
||||
## Docs
|
||||
|
||||
See [hooked.holllo.org](https://hooked.holllo.org) for documentation.
|
||||
|
||||
## Feedback
|
||||
|
||||
Found a problem or want to request a new feature? Email [helllo@holllo.org](mailto:helllo@holllo.org) and I'll see what I can do for you.
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705309234,
|
||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1705635624,
|
||||
"narHash": "sha256-DU0schxQOtBNO1c9hUsgYl+QMOXQMfRT7Qw/mg+ayno=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4471857c0a4a8a0ffc7bdbeaf1b998746ce12a82",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681358109,
|
||||
"narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705630663,
|
||||
"narHash": "sha256-f+kcR17ZtwMyCEtNAfpD0Mv6qObNKoJ41l+6deoaXi8=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "47cac072a313d9cce884b9ea418d2bf712fa23dd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, rust-overlay }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs { inherit system overlays; };
|
||||
in
|
||||
{
|
||||
devShells.default = import ./shell.nix { inherit pkgs; };
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
This file is automatically generated using the cli-reference subcommand.
|
||||
Use `cargo run -- cli-reference` to generate it.
|
||||
|
||||
// ANCHOR: install
|
||||
$ hooked install --help
|
||||
Install Hooked into ".git/hooks"
|
||||
|
||||
Usage: hooked install [OPTIONS]
|
||||
|
||||
Options:
|
||||
--overwrite Overwrite existing files
|
||||
-c, --config <CONFIG> Path to a Hooked configuration [default: Hooked.toml]
|
||||
-h, --help Print help information
|
||||
-V, --version Print version information
|
||||
// ANCHOR_END: install
|
||||
// ANCHOR: run
|
||||
$ hooked run --help
|
||||
Manually run hooks
|
||||
|
||||
Usage: hooked run [OPTIONS] <HOOK_TYPE>
|
||||
|
||||
Arguments:
|
||||
<HOOK_TYPE> The hook type to run [possible values: pre-commit]
|
||||
|
||||
Options:
|
||||
-c, --config <CONFIG> Path to a Hooked configuration [default: Hooked.toml]
|
||||
-h, --help Print help information
|
||||
-V, --version Print version information
|
||||
// ANCHOR_END: run
|
||||
// ANCHOR: uninstall
|
||||
$ hooked uninstall --help
|
||||
Remove installed hooks
|
||||
|
||||
Usage: hooked uninstall [OPTIONS]
|
||||
|
||||
Options:
|
||||
--all Remove hooks not installed by Hooked
|
||||
-c, --config <CONFIG> Path to a Hooked configuration [default: Hooked.toml]
|
||||
-h, --help Print help information
|
||||
-V, --version Print version information
|
||||
// ANCHOR_END: uninstall
|
||||
|
|
@ -3,16 +3,7 @@
|
|||
The `install` command creates the scripts inside `.git/hooks`.
|
||||
|
||||
```sh
|
||||
$ hooked install --help
|
||||
Install Hooked into ".git/hooks"
|
||||
|
||||
Usage: hooked install [OPTIONS]
|
||||
|
||||
Options:
|
||||
--overwrite Overwrite existing files
|
||||
-c, --config <CONFIG> Path to a Hooked configuration [default: Hooked.toml]
|
||||
-h, --help Print help information
|
||||
-V, --version Print version information
|
||||
{{#include ../cli-reference.txt:install}}
|
||||
```
|
||||
|
||||
Below is the default script template that Hooked uses, where `hook_type` is the type of hook to run (like `pre-commit`) and `config_path` is the `general.config` field from the parsed configuration.
|
||||
|
@ -20,3 +11,7 @@ Below is the default script template that Hooked uses, where `hook_type` is the
|
|||
```sh
|
||||
{{#include ../../../hooked-cli/source/templates/default.sh}}
|
||||
```
|
||||
|
||||
You can provide your own template by using the `general.template` configuration setting. If you do, make sure you include a line somewhere that says `# Installed by Hooked.` for the [uninstall CLI command][cli-uninstall].
|
||||
|
||||
[cli-uninstall]: ./uninstall.md
|
||||
|
|
|
@ -2,17 +2,6 @@
|
|||
|
||||
The `run` command manually runs configured hooks.
|
||||
|
||||
```
|
||||
$ hooked run --help
|
||||
Manually run hooks
|
||||
|
||||
Usage: hooked run [OPTIONS] <HOOK_TYPE>
|
||||
|
||||
Arguments:
|
||||
<HOOK_TYPE> The hook type to run [possible values: pre-commit]
|
||||
|
||||
Options:
|
||||
-c, --config <CONFIG> Path to a Hooked configuration [default: Hooked.toml]
|
||||
-h, --help Print help information
|
||||
-V, --version Print version information
|
||||
```sh
|
||||
{{#include ../cli-reference.txt:run}}
|
||||
```
|
||||
|
|
|
@ -3,16 +3,7 @@
|
|||
The `uninstall` command removes script files inside `.git/hooks`.
|
||||
|
||||
```sh
|
||||
hooked uninstall --help
|
||||
Remove installed hooks
|
||||
|
||||
Usage: hooked uninstall [OPTIONS]
|
||||
|
||||
Options:
|
||||
--all Remove hooks not installed by Hooked
|
||||
-c, --config <CONFIG> Path to a Hooked configuration [default: Hooked.toml]
|
||||
-h, --help Print help information
|
||||
-V, --version Print version information
|
||||
{{#include ../cli-reference.txt:uninstall}}
|
||||
```
|
||||
|
||||
By default Hooked will only remove scripts that have a `# Installed by Hooked.` line in them, using `--all` however will remove all script files.
|
||||
|
|
|
@ -10,11 +10,13 @@ The `general` [table][toml-table] is for main Hooked configuration.
|
|||
|-----|------|---------|-------------|
|
||||
| config | String | Hooked.toml | The configuration file to use. If your configuration file isn't `Hooked.toml` you should set this accordingly. |
|
||||
| directory | String | hooks | The directory Hooked looks in for anything related to files. For example: scripts, templates, etc. |
|
||||
| template | Optional string | | Path to a custom template to be used when installing scripts. See the [install CLI command][cli-install] for more details. |
|
||||
|
||||
```toml
|
||||
[general]
|
||||
config = "Hooked.toml"
|
||||
directory = "hooks"
|
||||
template = "template.sh"
|
||||
```
|
||||
|
||||
## Pre-commit
|
||||
|
@ -27,6 +29,7 @@ Pre-commit hooks are defined using `pre_commit` [arrays of tables][toml-arrays-o
|
|||
| command[^command-and-script] | String | | A command to run when the hook is called. |
|
||||
| script[^command-and-script] | String | | A script to run when the hook is called. This script should be executable and be located inside the configured general directory. |
|
||||
| on_failure | String | stop | What to do when the hook task returns a non-zero status code. Can be either "continue" or "stop". |
|
||||
| staged | Optional list of strings | | A list of [globs][globset-docs] that will be checked against staged files. If none of the globs match the hook will be skipped. With no globs defined at all the hook will always run. |
|
||||
|
||||
```toml
|
||||
[[pre_commit]]
|
||||
|
@ -37,11 +40,14 @@ command = "echo \"Hey, $USER!\""
|
|||
name = "Script Example"
|
||||
script = "example.sh"
|
||||
on_failure = "continue"
|
||||
staged = ["*.txt"]
|
||||
```
|
||||
|
||||
## Footnotes
|
||||
|
||||
[^command-and-script]: When both a command and script are defined in a hook, *only* the command will be run.
|
||||
|
||||
[cli-install]: ../cli/install.md
|
||||
[globset-docs]: https://docs.rs/globset/0.4.9/globset/#syntax
|
||||
[toml-table]: https://toml.io/en/v1.0.0#table
|
||||
[toml-arrays-of-tables]: https://toml.io/en/v1.0.0#array-of-tables
|
||||
|
|
|
@ -15,4 +15,13 @@ cargo install hooked-cli
|
|||
|
||||
Precompiled `x86_64-unknown-linux-gnu` binaries are available on the [Releases page][releases].
|
||||
|
||||
## Debian & Derivatives
|
||||
|
||||
An amd64 `.deb` file is available on the [Releases page][releases].
|
||||
|
||||
```sh
|
||||
# Don't forget to change <version>.
|
||||
dpkg --install hooked-cli_<version>_amd64.deb
|
||||
```
|
||||
|
||||
[releases]: https://git.bauke.xyz/Holllo/hooked/releases
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
[package]
|
||||
name = "hooked-cli"
|
||||
description = "Git hooks manager."
|
||||
documentation = "https://hooked.holllo.org"
|
||||
homepage = "https://hooked.holllo.org"
|
||||
repository = "https://git.bauke.xyz/Holllo/hooked"
|
||||
readme = "../README.md"
|
||||
license = "AGPL-3.0-or-later"
|
||||
version = "0.1.0"
|
||||
authors = ["Holllo <helllo@holllo.org>"]
|
||||
|
@ -11,22 +14,27 @@ edition = "2021"
|
|||
name = "hooked"
|
||||
path = "source/main.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
color-eyre = "0.6.2"
|
||||
owo-colors = "3.5.0"
|
||||
globset = "0.4.14"
|
||||
lazy_static = "1.4.0"
|
||||
owo-colors = "4.0.0"
|
||||
subprocess = "0.2.9"
|
||||
supports-color = "1.3.0"
|
||||
tera = "1.17.1"
|
||||
supports-color = "2.1.0"
|
||||
tera = "1.19.1"
|
||||
|
||||
[dependencies.clap]
|
||||
features = ["derive"]
|
||||
version = "4.0.18"
|
||||
version = "4.4.18"
|
||||
|
||||
[dependencies.hooked-config]
|
||||
path = "../hooked-config"
|
||||
version = "0.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2.0.5"
|
||||
insta = "1.21.0"
|
||||
test-case = "2.2.2"
|
||||
assert_cmd = "2.0.13"
|
||||
insta = "1.34.0"
|
||||
test-case = "3.3.1"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
LICENSE
|
|
@ -0,0 +1,52 @@
|
|||
//! The `cli-reference` subcommand, only available in debug mode.
|
||||
|
||||
use std::{fs::write, process::Command, str};
|
||||
|
||||
use {
|
||||
color_eyre::Result,
|
||||
hooked_config::Config,
|
||||
tera::{Context, Tera},
|
||||
};
|
||||
|
||||
use crate::cli::CliReferenceArgs;
|
||||
|
||||
/// The CLI reference template.
|
||||
const REFERENCE_TEMPLATE: &str = include_str!("../templates/cli-reference.txt");
|
||||
|
||||
/// The `cli-reference` subcommand.
|
||||
pub fn hooked_cli_reference(
|
||||
_config: Config,
|
||||
args: CliReferenceArgs,
|
||||
) -> Result<()> {
|
||||
let out_path = if args.output.is_dir() {
|
||||
args.output.join("cli-reference.txt")
|
||||
} else {
|
||||
args.output
|
||||
};
|
||||
|
||||
let commands = {
|
||||
let mut commands = vec![];
|
||||
let commands_to_document = &["install", "run", "uninstall"];
|
||||
|
||||
for command_name in commands_to_document {
|
||||
let output = Command::new("cargo")
|
||||
.env("NO_COLOR", "1")
|
||||
.args(["run", "-q", "--", command_name, "--help"])
|
||||
.output()
|
||||
.unwrap();
|
||||
let usage = str::from_utf8(&output.stdout).unwrap().trim().to_string();
|
||||
commands.push((command_name.to_string(), usage))
|
||||
}
|
||||
|
||||
commands
|
||||
};
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("commands", &commands);
|
||||
write(
|
||||
out_path,
|
||||
Tera::one_off(REFERENCE_TEMPLATE, &context, false)?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//! The `install` subcommand.
|
||||
use std::{
|
||||
fs::{read_to_string, set_permissions, write, Permissions},
|
||||
os::unix::fs::PermissionsExt,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use {
|
||||
color_eyre::{eyre::eyre, Result},
|
||||
hooked_config::Config,
|
||||
tera::{Context, Tera},
|
||||
};
|
||||
|
||||
use crate::{cli::InstallArgs, DEFAULT_TEMPLATE, HOOK_TYPES};
|
||||
|
||||
/// The `install` subcommand.
|
||||
pub fn hooked_install(config: Config, args: InstallArgs) -> Result<()> {
|
||||
let silent = args.silent;
|
||||
let git_hooks_dir = PathBuf::from(".git/hooks/");
|
||||
if !git_hooks_dir.exists() {
|
||||
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
|
||||
}
|
||||
|
||||
let hooked_directory = config.general.directory;
|
||||
for hook_type in HOOK_TYPES {
|
||||
let mut context = Context::new();
|
||||
context.insert("config_path", &config.general.config);
|
||||
context.insert("hook_type", hook_type);
|
||||
|
||||
let hook_path = git_hooks_dir.join(hook_type);
|
||||
if hook_path.exists() && !args.overwrite {
|
||||
if !silent {
|
||||
println!(
|
||||
"{:?} exists, use --overwrite to replace the existing file",
|
||||
hook_path
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let template = match config.general.template.as_ref() {
|
||||
Some(template_path) => {
|
||||
read_to_string(hooked_directory.join(template_path))?
|
||||
}
|
||||
None => DEFAULT_TEMPLATE.to_string(),
|
||||
};
|
||||
|
||||
write(&hook_path, Tera::one_off(&template, &context, false)?)?;
|
||||
set_permissions(hook_path, Permissions::from_mode(0o775))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -2,11 +2,22 @@
|
|||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use {
|
||||
clap::{Args as Arguments, Parser, Subcommand},
|
||||
hooked_config::NoiseLevel,
|
||||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
mod cli_reference;
|
||||
mod install;
|
||||
mod run;
|
||||
mod uninstall;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub use cli_reference::hooked_cli_reference;
|
||||
pub use install::hooked_install;
|
||||
pub use run::hooked_run;
|
||||
pub use uninstall::hooked_uninstall;
|
||||
|
||||
/// CLI arguments struct using [`clap::Parser`].
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -26,23 +37,55 @@ pub struct Args {
|
|||
#[derive(Debug, Subcommand)]
|
||||
pub enum MainSubcommands {
|
||||
/// Install Hooked into ".git/hooks".
|
||||
Install {
|
||||
/// Overwrite existing files.
|
||||
#[clap(long)]
|
||||
overwrite: bool,
|
||||
},
|
||||
Install(InstallArgs),
|
||||
|
||||
/// Remove installed hooks.
|
||||
Uninstall {
|
||||
/// Remove hooks not installed by Hooked.
|
||||
#[clap(long)]
|
||||
all: bool,
|
||||
},
|
||||
Uninstall(UninstallArgs),
|
||||
|
||||
/// Manually run hooks.
|
||||
Run {
|
||||
/// The hook type to run.
|
||||
#[clap(value_parser = crate::HOOK_TYPES)]
|
||||
hook_type: String,
|
||||
},
|
||||
Run(RunArgs),
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
/// Generate the CLI reference file for the mdBook.
|
||||
CliReference(CliReferenceArgs),
|
||||
}
|
||||
|
||||
/// The `install` subcommand arguments.
|
||||
#[derive(Debug, Arguments)]
|
||||
pub struct InstallArgs {
|
||||
/// Overwrite existing files.
|
||||
#[clap(long)]
|
||||
pub overwrite: bool,
|
||||
|
||||
/// Don't output any information.
|
||||
#[clap(long)]
|
||||
pub silent: bool,
|
||||
}
|
||||
|
||||
/// The `uninstall` subcommand arguments.
|
||||
#[derive(Debug, Arguments)]
|
||||
pub struct UninstallArgs {
|
||||
/// Remove hooks not installed by Hooked.
|
||||
#[clap(long)]
|
||||
pub all: bool,
|
||||
}
|
||||
|
||||
/// The `run` subcommand arguments.
|
||||
#[derive(Debug, Arguments)]
|
||||
pub struct RunArgs {
|
||||
/// The hook type to run.
|
||||
#[clap(value_parser = crate::HOOK_TYPES)]
|
||||
pub hook_type: String,
|
||||
|
||||
/// The noise level to override for all hooks.
|
||||
#[clap(long)]
|
||||
pub noise_level: Option<NoiseLevel>,
|
||||
}
|
||||
|
||||
/// The `cli-reference` subcommand arguments.
|
||||
#[derive(Debug, Arguments)]
|
||||
pub struct CliReferenceArgs {
|
||||
/// Path where the CLI reference file should be generated.
|
||||
#[clap(short, long, default_value = "hooked-book/source/")]
|
||||
pub output: PathBuf,
|
||||
}
|
||||
|
|
|
@ -5,38 +5,57 @@ use std::{io::Read, process::exit};
|
|||
use {
|
||||
color_eyre::{eyre::eyre, Result},
|
||||
hooked_config::{Config, ExitAction},
|
||||
owo_colors::{OwoColorize, Style},
|
||||
owo_colors::OwoColorize,
|
||||
subprocess::{Exec, Redirection},
|
||||
supports_color::Stream,
|
||||
};
|
||||
|
||||
use crate::utilities::plural;
|
||||
use crate::{
|
||||
cli::RunArgs,
|
||||
printer::{print, PrintType, PRINT_STYLE},
|
||||
utilities::{globset_from_strings, plural},
|
||||
};
|
||||
|
||||
/// The `run` subcommand.
|
||||
pub fn hooked_run(config: Config, hook_type: String) -> Result<()> {
|
||||
let (success_style, warn_style, error_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(),
|
||||
)
|
||||
} else {
|
||||
(Style::new(), Style::new(), Style::new())
|
||||
};
|
||||
pub fn hooked_run(config: Config, args: RunArgs) -> Result<()> {
|
||||
let cli_noise_level = args.noise_level.as_ref();
|
||||
let global_noise_level = &config.general.noise_level;
|
||||
|
||||
if hook_type == "pre-commit" {
|
||||
if args.hook_type == "pre-commit" {
|
||||
let hook_count = config.pre_commit.len();
|
||||
println!(
|
||||
"Hooked: Running {} pre-commit {}.",
|
||||
hook_count,
|
||||
plural(hook_count, "hook", None)
|
||||
print(
|
||||
format!(
|
||||
"Hooked: Running {} pre-commit {}.",
|
||||
hook_count,
|
||||
plural(hook_count, "hook", None)
|
||||
),
|
||||
cli_noise_level.unwrap_or(global_noise_level),
|
||||
PrintType::Info,
|
||||
);
|
||||
|
||||
for hook in config.pre_commit {
|
||||
'hook_loop: for hook in config.pre_commit {
|
||||
let hook_name = hook.name.unwrap_or_else(|| "Unnamed Hook".to_string());
|
||||
|
||||
if !hook.staged.is_empty() {
|
||||
let globs = globset_from_strings(&hook.staged)?;
|
||||
|
||||
let staged_files = Exec::cmd("git")
|
||||
.args(&["diff", "--name-only", "--cached"])
|
||||
.capture()?
|
||||
.stdout_str();
|
||||
if !staged_files.lines().any(|line| globs.is_match(line)) {
|
||||
print(
|
||||
format!(
|
||||
"\t{} {}",
|
||||
"≫".style(PRINT_STYLE.skipped),
|
||||
hook_name.style(PRINT_STYLE.skipped)
|
||||
),
|
||||
cli_noise_level.unwrap_or(global_noise_level),
|
||||
PrintType::Info,
|
||||
);
|
||||
continue 'hook_loop;
|
||||
}
|
||||
}
|
||||
|
||||
let command = match (hook.task.command, hook.task.script) {
|
||||
(Some(command), _) => Ok(Exec::shell(command)),
|
||||
|
||||
|
@ -66,16 +85,32 @@ pub fn hooked_run(config: Config, hook_type: String) -> Result<()> {
|
|||
output
|
||||
};
|
||||
|
||||
let (stop, print_output, prefix, style) =
|
||||
let (stop, print_output, prefix, style, print_type) =
|
||||
match (exit_status.success(), hook.on_failure) {
|
||||
(true, _) => (false, false, "✓", success_style),
|
||||
(false, ExitAction::Continue) => (false, true, "⚠", warn_style),
|
||||
(false, ExitAction::Stop) => (true, true, "✗", error_style),
|
||||
(true, _) => {
|
||||
(false, false, "✓", PRINT_STYLE.success, PrintType::Info)
|
||||
}
|
||||
(false, ExitAction::Continue) => {
|
||||
(false, true, "⚠", PRINT_STYLE.warn, PrintType::Warn)
|
||||
}
|
||||
(false, ExitAction::Stop) => {
|
||||
(true, true, "✗", PRINT_STYLE.error, PrintType::Error)
|
||||
}
|
||||
};
|
||||
|
||||
println!("\t{} {}", prefix.style(style), hook_name.style(style));
|
||||
let hook_noise_level =
|
||||
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 {
|
||||
println!("{}", output);
|
||||
print(
|
||||
output,
|
||||
cli_noise_level.unwrap_or(hook_noise_level),
|
||||
PrintType::Info,
|
||||
);
|
||||
}
|
||||
|
||||
if stop {
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//! The `uninstall` subcommand.
|
||||
|
||||
use std::{
|
||||
fs::{read_to_string, remove_file},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use {
|
||||
color_eyre::{eyre::eyre, Result},
|
||||
hooked_config::Config,
|
||||
};
|
||||
|
||||
use crate::{cli::UninstallArgs, HOOK_TYPES};
|
||||
|
||||
/// The `uninstall` subcommand.
|
||||
pub fn hooked_uninstall(_config: Config, args: UninstallArgs) -> Result<()> {
|
||||
let git_hooks_dir = PathBuf::from(".git/hooks/");
|
||||
if !git_hooks_dir.exists() {
|
||||
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
|
||||
}
|
||||
|
||||
for hook_type in HOOK_TYPES {
|
||||
let hook_path = git_hooks_dir.join(hook_type);
|
||||
if !hook_path.exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let hook_contents = read_to_string(&hook_path)?;
|
||||
if args.all || hook_contents.contains("# Installed by Hooked.") {
|
||||
remove_file(hook_path)?;
|
||||
} else {
|
||||
println!(
|
||||
"{:?} wasn't installed by Hooked, use --all to remove it",
|
||||
hook_path
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -2,20 +2,10 @@
|
|||
//!
|
||||
//! > **Git hooks manager.**
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![warn(missing_docs, clippy::missing_docs_in_private_items)]
|
||||
|
||||
use std::{
|
||||
fs::{read_to_string, remove_file, set_permissions, write, Permissions},
|
||||
os::unix::fs::PermissionsExt,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use {
|
||||
clap::Parser,
|
||||
color_eyre::{eyre::eyre, install, Result},
|
||||
color_eyre::{install, Result},
|
||||
hooked_config::Config,
|
||||
tera::{Context, Tera},
|
||||
};
|
||||
|
||||
use crate::cli::{Args, MainSubcommands};
|
||||
|
@ -27,6 +17,7 @@ pub const DEFAULT_TEMPLATE: &str = include_str!("templates/default.sh");
|
|||
pub const HOOK_TYPES: [&str; 1] = ["pre-commit"];
|
||||
|
||||
mod cli;
|
||||
mod printer;
|
||||
mod utilities;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
@ -35,61 +26,22 @@ fn main() -> Result<()> {
|
|||
let args = Args::parse();
|
||||
let config = Config::from_toml_file(args.config)?;
|
||||
|
||||
let git_hooks_dir = PathBuf::from(".git/hooks/");
|
||||
|
||||
match args.command {
|
||||
MainSubcommands::Install { overwrite } => {
|
||||
if !git_hooks_dir.exists() {
|
||||
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
|
||||
}
|
||||
|
||||
for hook_type in HOOK_TYPES {
|
||||
let mut context = Context::new();
|
||||
context.insert("config_path", &config.general.config);
|
||||
context.insert("hook_type", hook_type);
|
||||
|
||||
let hook_path = git_hooks_dir.join(hook_type);
|
||||
if hook_path.exists() && !overwrite {
|
||||
println!(
|
||||
"{:?} exists, use --overwrite to replace the existing file",
|
||||
hook_path
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
write(
|
||||
&hook_path,
|
||||
Tera::one_off(DEFAULT_TEMPLATE, &context, false)?,
|
||||
)?;
|
||||
set_permissions(hook_path, Permissions::from_mode(0o775))?;
|
||||
}
|
||||
MainSubcommands::Install(sub_args) => {
|
||||
cli::hooked_install(config, sub_args)?;
|
||||
}
|
||||
|
||||
MainSubcommands::Uninstall { all } => {
|
||||
if !git_hooks_dir.exists() {
|
||||
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
|
||||
}
|
||||
|
||||
for hook_type in HOOK_TYPES {
|
||||
let hook_path = git_hooks_dir.join(hook_type);
|
||||
if !hook_path.exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let hook_contents = read_to_string(&hook_path)?;
|
||||
if all || hook_contents.contains("# Installed by Hooked.") {
|
||||
remove_file(hook_path)?;
|
||||
} else {
|
||||
println!(
|
||||
"{:?} wasn't installed by Hooked, use --all to remove it",
|
||||
hook_path
|
||||
);
|
||||
}
|
||||
}
|
||||
MainSubcommands::Uninstall(sub_args) => {
|
||||
cli::hooked_uninstall(config, sub_args)?;
|
||||
}
|
||||
|
||||
MainSubcommands::Run { hook_type } => {
|
||||
cli::hooked_run(config, hook_type)?;
|
||||
MainSubcommands::Run(sub_args) => {
|
||||
cli::hooked_run(config, sub_args)?;
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
MainSubcommands::CliReference(sub_args) => {
|
||||
cli::hooked_cli_reference(config, sub_args)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
//! 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 successful 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}")
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
This file is automatically generated using the cli-reference subcommand.
|
||||
Use `cargo run -- cli-reference` to generate it.
|
||||
|
||||
{% for command in commands %}
|
||||
{%- set name = command.0 -%}
|
||||
{%- set usage = command.1 -%}
|
||||
// ANCHOR: {{ name }}
|
||||
$ hooked {{ name }} --help
|
||||
{{ usage }}
|
||||
// ANCHOR_END: {{ name }}
|
||||
{% endfor %}
|
|
@ -1,14 +0,0 @@
|
|||
//! Miscellaneous utilities.
|
||||
|
||||
/// Simple function to create a pluralized string.
|
||||
pub fn plural(count: usize, singular: &str, plural: Option<&str>) -> String {
|
||||
if count == 1 {
|
||||
return singular.to_string();
|
||||
}
|
||||
|
||||
if let Some(plural) = plural {
|
||||
return plural.to_string();
|
||||
}
|
||||
|
||||
format!("{singular}s")
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//! Miscellaneous utilities.
|
||||
|
||||
use color_eyre::Result;
|
||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||
|
||||
/// Simple function to create a pluralized string.
|
||||
pub fn plural(count: usize, singular: &str, plural: Option<&str>) -> String {
|
||||
if count == 1 {
|
||||
return singular.to_string();
|
||||
}
|
||||
|
||||
if let Some(plural) = plural {
|
||||
return plural.to_string();
|
||||
}
|
||||
|
||||
format!("{singular}s")
|
||||
}
|
||||
|
||||
/// Create a [`GlobSet`] from a list of strings.
|
||||
pub fn globset_from_strings(input: &[String]) -> Result<GlobSet> {
|
||||
let mut builder = GlobSetBuilder::new();
|
||||
for glob in input {
|
||||
builder.add(Glob::new(glob)?);
|
||||
}
|
||||
|
||||
builder.build().map_err(Into::into)
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
[package]
|
||||
name = "hooked-config"
|
||||
description = "Configuration for Hooked."
|
||||
documentation = "https://docs.rs/hooked-config"
|
||||
homepage = "https://hooked.holllo.org"
|
||||
repository = "https://git.bauke.xyz/Holllo/hooked"
|
||||
readme = "../README.md"
|
||||
license = "AGPL-3.0-or-later"
|
||||
version = "0.1.0"
|
||||
authors = ["Holllo <helllo@holllo.org>"]
|
||||
|
@ -10,14 +13,17 @@ edition = "2021"
|
|||
[lib]
|
||||
path = "source/lib.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
color-eyre = "0.6.2"
|
||||
toml = "0.5.9"
|
||||
toml = "0.8.8"
|
||||
|
||||
[dependencies.serde]
|
||||
features = ["derive"]
|
||||
version = "1.0.147"
|
||||
version = "1.0.195"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = "1.21.0"
|
||||
test-case = "2.2.2"
|
||||
insta = "1.34.0"
|
||||
test-case = "3.3.1"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
LICENSE
|
|
@ -6,7 +6,9 @@ use serde::{Deserialize, Serialize};
|
|||
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExitAction {
|
||||
/// Regardless of the hook's exit code, allow Hooked to continue.
|
||||
Continue,
|
||||
/// Stop on a non-zero hook exit code.
|
||||
Stop,
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ use std::path::PathBuf;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::NoiseLevel;
|
||||
|
||||
/// General Hooked configuration.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
|
@ -13,6 +15,12 @@ pub struct General {
|
|||
|
||||
/// The directory to use for hooks.
|
||||
pub directory: PathBuf,
|
||||
|
||||
/// The noise level tasks should output logs with by default.
|
||||
pub noise_level: NoiseLevel,
|
||||
|
||||
/// Path to a script template for use with the install subcommand.
|
||||
pub template: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Default for General {
|
||||
|
@ -20,6 +28,8 @@ impl Default for General {
|
|||
Self {
|
||||
config: PathBuf::from("Hooked.toml"),
|
||||
directory: PathBuf::from("hooks"),
|
||||
noise_level: NoiseLevel::default(),
|
||||
template: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,13 @@ use {
|
|||
|
||||
mod exit_action;
|
||||
mod general;
|
||||
mod noise_level;
|
||||
mod pre_commit;
|
||||
mod task;
|
||||
|
||||
pub use exit_action::*;
|
||||
pub use general::*;
|
||||
pub use noise_level::*;
|
||||
pub use pre_commit::*;
|
||||
pub use task::*;
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
//! The noise level Hooked should output logs with.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The noise level Hooked should output logs with.
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum NoiseLevel {
|
||||
/// Output only errors.
|
||||
Quiet,
|
||||
/// Output everything.
|
||||
Loud,
|
||||
/// Print a list of tasks and output warnings and errors, this is the default.
|
||||
Standard,
|
||||
/// The same as [`NoiseLevel::Standard`] except don't output task names or
|
||||
/// warnings.
|
||||
Minimal,
|
||||
}
|
||||
|
||||
impl Default for NoiseLevel {
|
||||
fn default() -> Self {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{ExitAction, Task};
|
||||
use crate::{ExitAction, NoiseLevel, Task};
|
||||
|
||||
/// A pre-commit hook.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
|
@ -11,10 +11,17 @@ pub struct PreCommit {
|
|||
/// Display name for this hook.
|
||||
pub name: Option<String>,
|
||||
|
||||
/// The noise level this task should output with.
|
||||
pub noise_level: Option<NoiseLevel>,
|
||||
|
||||
/// What to do when the hook exits with a non-zero status code.
|
||||
#[serde(default)]
|
||||
pub on_failure: ExitAction,
|
||||
|
||||
/// List of globs to check against staged files.
|
||||
#[serde(default)]
|
||||
pub staged: Vec<String>,
|
||||
|
||||
/// Task to perform when this hook is called.
|
||||
#[serde(flatten)]
|
||||
pub task: Task,
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
[general]
|
||||
directory = "hooked"
|
||||
noise_level = "minimal"
|
||||
template = "test.sh"
|
||||
|
||||
[[pre_commit]]
|
||||
name = "Pre Commit 1"
|
||||
command = "exit 0"
|
||||
staged = ["*.txt"]
|
||||
on_failure = "continue"
|
||||
|
||||
[[pre_commit]]
|
||||
name = "Pre Commit 2"
|
||||
noise_level = "loud"
|
||||
script = "test.sh"
|
||||
on_failure = "stop"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
hooked_config::{Config, ExitAction, PreCommit, Task},
|
||||
hooked_config::{Config, ExitAction, NoiseLevel, PreCommit, Task},
|
||||
toml::to_string_pretty,
|
||||
};
|
||||
|
||||
|
@ -9,7 +9,9 @@ use insta::assert_snapshot;
|
|||
fn test_serialize() {
|
||||
let pre_commit_command = PreCommit {
|
||||
name: Some("Command Test".to_string()),
|
||||
noise_level: None,
|
||||
on_failure: ExitAction::Continue,
|
||||
staged: vec!["*.txt".to_string()],
|
||||
task: Task {
|
||||
command: Some("exit 0".to_string()),
|
||||
script: None,
|
||||
|
@ -18,7 +20,9 @@ fn test_serialize() {
|
|||
|
||||
let pre_commit_script = PreCommit {
|
||||
name: Some("Script Test".to_string()),
|
||||
noise_level: Some(NoiseLevel::Loud),
|
||||
on_failure: ExitAction::Stop,
|
||||
staged: vec![],
|
||||
task: Task {
|
||||
command: None,
|
||||
script: Some("test.sh".into()),
|
||||
|
|
|
@ -6,11 +6,15 @@ Config {
|
|||
general: General {
|
||||
config: "Hooked.toml",
|
||||
directory: "hooks",
|
||||
noise_level: Standard,
|
||||
template: None,
|
||||
},
|
||||
pre_commit: [
|
||||
PreCommit {
|
||||
name: None,
|
||||
noise_level: None,
|
||||
on_failure: Stop,
|
||||
staged: [],
|
||||
task: Task {
|
||||
command: None,
|
||||
script: None,
|
||||
|
|
|
@ -6,13 +6,21 @@ Config {
|
|||
general: General {
|
||||
config: "Hooked.toml",
|
||||
directory: "hooked",
|
||||
noise_level: Minimal,
|
||||
template: Some(
|
||||
"test.sh",
|
||||
),
|
||||
},
|
||||
pre_commit: [
|
||||
PreCommit {
|
||||
name: Some(
|
||||
"Pre Commit 1",
|
||||
),
|
||||
noise_level: None,
|
||||
on_failure: Continue,
|
||||
staged: [
|
||||
"*.txt",
|
||||
],
|
||||
task: Task {
|
||||
command: Some(
|
||||
"exit 0",
|
||||
|
@ -24,7 +32,11 @@ Config {
|
|||
name: Some(
|
||||
"Pre Commit 2",
|
||||
),
|
||||
noise_level: Some(
|
||||
Loud,
|
||||
),
|
||||
on_failure: Stop,
|
||||
staged: [],
|
||||
task: Task {
|
||||
command: None,
|
||||
script: Some(
|
||||
|
|
|
@ -3,16 +3,20 @@ source: hooked-config/tests/serialize.rs
|
|||
expression: to_string_pretty(&config).unwrap()
|
||||
---
|
||||
[general]
|
||||
config = 'Hooked.toml'
|
||||
directory = 'hooks'
|
||||
config = "Hooked.toml"
|
||||
directory = "hooks"
|
||||
noise_level = "standard"
|
||||
|
||||
[[pre_commit]]
|
||||
name = 'Command Test'
|
||||
on_failure = 'continue'
|
||||
command = 'exit 0'
|
||||
name = "Command Test"
|
||||
on_failure = "continue"
|
||||
staged = ["*.txt"]
|
||||
command = "exit 0"
|
||||
|
||||
[[pre_commit]]
|
||||
name = 'Script Test'
|
||||
on_failure = 'stop'
|
||||
script = 'test.sh'
|
||||
name = "Script Test"
|
||||
noise_level = "loud"
|
||||
on_failure = "stop"
|
||||
staged = []
|
||||
script = "test.sh"
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "stable"
|
||||
components = ["cargo", "clippy", "rustfmt", "rust-src"]
|
|
@ -0,0 +1,33 @@
|
|||
{ pkgs ? import <nixpkgs> { } }:
|
||||
|
||||
with pkgs;
|
||||
|
||||
let
|
||||
rustup-toolchain = rust-bin.fromRustupToolchainFile ./rustup-toolchain.toml;
|
||||
in
|
||||
mkShell rec {
|
||||
packages = [
|
||||
cargo-audit
|
||||
cargo-edit
|
||||
cargo-insta
|
||||
cargo-make
|
||||
cargo-outdated
|
||||
cargo-tarpaulin
|
||||
mdbook
|
||||
mdbook-linkcheck
|
||||
rustup-toolchain
|
||||
typos
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
# Add the outputs directory to PATH where local tools will be installed.
|
||||
PATH="$PATH:$out/bin"
|
||||
|
||||
# If Hooked isn't installed, use cargo to install the local version of it.
|
||||
if ! [[ -x "$(command -v hooked)" ]]; then
|
||||
cargo install --path hooked-cli --root $out
|
||||
fi
|
||||
|
||||
hooked install --silent
|
||||
'';
|
||||
}
|
Loading…
Reference in New Issue