Husky 0.3.0

There is a newer version of this package available.
See the version list below for details.
dotnet tool install --global Husky --version 0.3.0                
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest # if you are setting up this repo
dotnet tool install --local Husky --version 0.3.0                
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Husky&version=0.3.0                
nuke :add-package Husky --version 0.3.0                

Husky.Net

GitHub Nuget Nuget (with prereleases) GitHub Workflow Status

Husky.Net WorkFlow

Introduction

Husky improves your commits and more 🐶 woof!

You can use it to lint your commit messages, run tests, lint code, etc... when you commit or push.

Features

  • Supports all Git hooks
  • Powered by modern new Git feature (core.hooksPath)
  • User-friendly messages
  • Supports macOS, Linux and Windows
  • Git GUIs
  • Custom directories
  • Monorepo
  • 🔥 Internal task runner!
  • 🔥 Multiple file states (staged, last-commit, git-files, etc...)
  • 🔥 Compatible with dotnet-format
  • 🔥 User-define arg variables
  • 🔥 CSharp scripts (csx)
  • 🔥 Supports gitflow hooks

If you already know what is the lint-staged or Husky (npm packages), this is very similar but you can use Husky.Net without having node, yarn, etc.. installed, with a lot of more features! 🚀🚀

Why use Hooks and Husky.Net?

We, as developers, love platforms like GitHub, GitLab, Atlassian, Azure DevOps etc., as our managed git system and collaboration platform. We also love clean code and keep inventing new linters and rules to enforce it. In my opinion, every commit should allow the codebase to deploy to production. There is nothing worse than commits like “fixed style errors” or “fixed build”. These are often small mistakes you want to know as early as possible in your development cycle. You don’t want to break the build for the next developer because he pulled your ‘mistake’ or waste precious build minutes of your CI server. Say you have asked your teammate to review your code; in the meantime, the build server rejects your code. That means you have to go back and fix this, and your teammate has to come back and possibly review again after the changes (i.e., approvals reset on new commit). Doing so would waste a lot of time and effort. Husky.Net offers a very simple way to start using git hooks or running certain tasks, write custom scripts using c# and more ...

A lot of features are coming soon, stay tuned! 👁️‍🗨️👀

Installation

# local installation (recommended)
cd <Your project root directory>
dotnet new tool-manifest
dotnet tool install Husky

# global installation
dotnet tool install --global Husky

Note: With the global installation, you don't need to add the dotnet prefix to the commands.

Setup husky for your project

cd <Your project root directory>
dotnet husky install

Add your first hook

dotnet husky add pre-commit -c "echo 'Husky is awesome!'"
git add .husky/pre-commit

Make a commit

git commit -m "Keep calm and commit"
# `echo 'Husky is awesome!'` will run every time you commit

Automate husky installation for other contributors

If you installed husky locally, just add the below code to one of your projects (*.csproj *.vbproj).

Important: Just make sure to update the working directory depending on your folder structure.

<Target Name="husky" BeforeTargets="Restore;CollectPackageReferences">
   <Exec Command="dotnet tool restore"  StandardOutputImportance="Low" StandardErrorImportance="High"/>
   <Exec Command="dotnet husky install" StandardOutputImportance="Low" StandardErrorImportance="High"
         WorkingDirectory="../../" />  
</Target>

If you have only one multiple target project (TargetFrameworks) add the bellow condition IsCrossTargetingBuild to the target tag to prevent multiple execution

<Target Name="husky" BeforeTargets="Restore;CollectPackageReferences" Condition="'$(IsCrossTargetingBuild)' == 'true'">
   ...

Or If you are using the npm, add the below code to your package.json file to automatically install husky after the installation process:

 "scripts": {
    "prepare": "dotnet tool restore && dotnet husky install"
 }

Task runner

Linting makes more sense when run before committing your code. By doing so you can ensure no errors go into the repository and enforce code style. But running a lint process on a whole project is slow, and linting results can be irrelevant. Ultimately you only want to lint files that will be committed.

After installation, you must have task-runner.json file in your .husky directory that you can use to define your tasks.

you can run and test your tasks with husky run command. Once you are sure that your tasks are working properly, you can add it to the hook.

e.g.

dotnet husky add pre-commit -c "dotnet husky run"

<details> <summary>A simple real-world example <code>task-runner.json</code></summary> <p>

{
   "tasks": [
      {
         "name": "dotnet-format",
         "group": "pre-commit",
         "command": "dotnet",
         "args": ["dotnet-format", "--include", "${staged}"],
         "include": ["**/*.cs", "**/*.vb"]
      },
      {
         "name": "eslint",
         "group": "pre-commit",
         "pathMode": "absolute",
         "cwd": "Client",
         "command": "npm",
         "args": ["run", "lint", "${staged}"],
         "include": ["**/*.ts", "**/*.vue", "**/*.js"]
      },
      {
         "name": "prettier",
         "group": "pre-commit",
         "pathMode": "absolute",
         "cwd": "Client",
         "command": "npx",
         "args": ["prettier", "--write", "${staged}"],
         "include": [
            "**/*.ts",
            "**/*.vue",
            "**/*.js",
            "**/*.json",
            "**/*.yml",
            "**/*.css",
            "**/*.scss"
         ]
      },
      {
         "name": "Welcome",
         "output": "always",
         "command": "bash",
         "args": ["-c", "echo Nice work! 🥂"],
         "windows": {
            "command": "cmd",
            "args": ["/c", "echo Nice work! 🥂"]
         }
      }
   ]
}

</p> </details>

<br>

Task configurations

Each task in task-runner.json is a JSON object with the following properties:


name optional type default description
command false string - path to the executable file or script or executable name
args true [string array] - command arguments
include true [array of glob] **/* glob pattern to select files
name true string command name of the task (recommended)
group true string - group of the task (usually it should be the hook name)
branch true string (regex) - run task on specific branches only
pathMode true [absolute, relative] relative file path style (relative or absolute)
cwd true string project root directory current working directory for the command, can be relative or absolute
output true [always, verbose, never] always output log level
exclude true [array of glob] - glob pattern to exclude files
windows true object - overrides all the above settings for windows

Glob patterns

Husky.Net supports the standard dotnet FileSystemGlobbing patterns for include or exclude task configurations. read more here


Arg Variables

There are some variables that you can use in your task arguments.

  • ${staged}
    • returns the list of currently staged files
  • ${last-commit}
    • returns last commit changed files
  • ${git-files}
    • returns the output of (git ls-files)
  • ${all-files}
    • returns the list of matched files using include/exclude, be careful with this variable, it will return all the files if you don't specify include or exclude
  • ${args}
    • returns the arguments passed directly to the husky run command using --args option

e.g."args": [ "${staged}" ]

user-defined variables

You can define your own variables by adding a task to the variables section in task-runner.json.

e.g: defining custom ${root-dir} variable to access root directory files

{
   "variables": [
      {
         "name": "root-dir",
         "command": "cmd",
         "args": ["/c", "dir", "/b"]
      }
   ],
   "tasks": [
      {
         "command": "cmd",
         "args": ["/c", "echo", "${root-dir}"]
      }
   ]
}

Using C# code in your git hooks

You can use the exec command to execute a C# script.

e.g.

dotnet husky exec <csx-file-path>
# e.g
# dotnet husky exec .husky/csx/hello.csx

Also, you can use your csx scripts in your tasks.

e.g task

{
   "command": "dotnet",
   "args": [ "husky", "exec", ".husky/csx/hello.csx"  ],
}

This repo also using a csharp script to lint the commit messages, you can check it here ( commit-lint.csx / commit-msg hook / task-runner.json )


Support

  • Don't forget to give a ⭐ on GitHub
  • Share your feedback and ideas to improve this tool
  • Share Husky.Net on your favorite social media and your friends
  • Write a blog post about Husky.Net
  • All contributions are welcome! Feel free to send pull requests

Credits

  • This tool inspired of husky & lint-staged and a few other tools, for DotNet, so make sure to support them too!

  • I'd also like to thank kaylumah for his article that gave me the csharp scripting support idea.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.1 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last updated
0.7.1 170,518 8/13/2024
0.7.0 125,339 6/16/2024
0.6.5 88,929 5/10/2024
0.6.4 457,929 12/17/2023
0.6.3 161,650 11/16/2023
0.6.2 149,126 9/19/2023
0.6.1 54,912 9/2/2023
0.6.1-test1 804 9/19/2023
0.6.0 10,826 8/29/2023
0.6.0-Preview4 1,003 6/8/2023
0.6.0-Preview2 1,044 4/17/2023
0.6.0-Preview1 1,137 2/26/2023
0.5.4 404,679 1/7/2023
0.5.4-preview2 1,140 1/7/2023
0.5.4-preview1 15,522 12/2/2022
0.5.2 82,056 10/8/2022
0.5.1 153,362 8/1/2022
0.5.0 1,566 7/30/2022 0.5.0 is deprecated because it has critical bugs.
0.4.4 97,779 5/18/2022
0.4.2 46,066 3/9/2022
0.4.1 1,243 3/9/2022
0.4.0 40,267 1/31/2022
0.4.0-preview-4 1,067 1/29/2022
0.4.0-preview-3 1,118 1/28/2022
0.3.2 7,245 1/15/2022
0.3.1 1,503 1/11/2022
0.3.0 60,923 1/5/2022
0.2.2 1,603 1/3/2022
0.2.1 1,195 12/31/2021
0.2.0 2,143 12/30/2021
0.1.2 1,219 12/29/2021
0.1.1 1,181 12/28/2021
0.0.9 1,210 12/28/2021
0.0.8 1,059 12/27/2021
0.0.7 1,142 12/27/2021