# Committee
> **Reminder**: While `Committee` is working great for my own use-case, there can be occasional bugs every now and then, if your workflow rely heavily on a Git workflow, proceed at your own risk. Otherwise a PR is very much welcomed!
---
Committee is a supercharged ⚡️ git hooks manager in pure Elixir.
What does supercharged mean? This is what supercharged means.
Supercharged means:
- You get to write ***code*** with your git hooks.
- You get to write ***Elixir*** code with your git hooks.
- You get to write ***any*** Elixir code with your git hooks.
- ***Any. Elixir. Code. ⚡️***
[Read on](https://github.com/edisonywh/committee#usage) to find out more!
## Installation
Get the latest version from [Hex](https://hex.pm/packages/committee)
```elixir
def deps do
[
{:committee, "~> 0.1.2", only: :dev, runtime: false}
]
end
```
## Usage
*Documentation can be also be found over on [HexDocs](https://hexdocs.pm/committee).*
After installing `Committee`, all you have to do is run
> `mix committee.install`
*Your existing git hooks will be backed-up and renamed from `hook` to `hook.old`*
You should see a `commit.exs` file being generated, that's where you'll be writing your hooks.
The file should look something like this:
```elixir
defmodule YourApp.Commit do
use Committee
import Committee.Helpers, only: [staged_files: 0]
# ...
# ...
#
# ## Example:
#
# def pre_commit do
# System.cmd("mix", ["format"] ++ staged_files())
# System.cmd("git", ["add"] ++ staged_files())
# end
#
# ...
#
end
```
To run code for a hook, write a function with the same name (in `snake_case`) as that hook. For a full list of git hooks in the wild, [checkout this list over here](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks).
To **abort** a commit, return in the form of `{:halt, reason}`.
To **print** a success message, return in the form of `{:ok, message}`.
If you find that Committee does not do what you want (do let me know how to improve!) and you want to stop using it, you can run the built-in uninstallation task: `mix committee.uninstall`. **This will restore your existing hooks backup too**.
For a list of `Committee` supported hooks, checkout `Committee.__hooks__/0`
For a list of `Committee` provided helpers (such as `staged_files/0`, `branch_name/0`, checkout `Committee.Helpers`)
*Currently only `pre_commit` and `post_commit` are supported, this is mostly because I haven't tested the other ones, rather than any technical limitation, but I don't see why it won't work for the others. PRs are welcomed!*
### What are git hooks?
If you're reading this, you're probably familiar with Git. We are all used to terms like `commit`, `rebase`, but did you know that Git ships with the ability to run a hook/callback when you run these actions?
This effectively means you can write code that gets executed when you do a `git commit`, or when you're commencing a `rebase`. Exciting innit? :)
### What is `Committee` trying to solve?
Git hooks are great, but in my experience, there are two issues with them:
#### 1) Hassle to set-up
I find that it's not exactly straightforward to write git hooks, here's my own flow of writing a git hook (true story):
- read up about the amazing git hooks (like you're doing now)
- navigate into `.git/hooks`
- `vim pre-commit`
- *writes in bash* <sup>1</sup>
- make `pre-commit` into an executable.
- *Wait, how do you make it into an exectuable?*
- *googles for 5 mins*
- Ah, `chmod +x pre-commit`
I wanted an easier process for myself, but also read on to find out more.
#### 2) Difficult to share with team
Git hooks live in the `.git/hooks/` folder, and **`.git` folder isn't versioned**, this means that whatever you've just done in the [previous step](https://github.com/edisonywh/committee#step-1) would not work for your other team members.
No biggie aye? You just have to get **each and every one** of your teammate to repeat step 1.
Did I also mentioned that if you decided to update the `pre-commit` script (for example, you have a change in branchs' naming convention), you'd have to again, convince everyone in your team to repeat step 1?
*Yup.*
#### Get yourself a `Committee`!
The premise of `Committee` is simple, it solves the aforementioned problems like so:
> Hassle to set-up
Well for starters, you don't have to write any bash script<sup>1</sup>. Bash scripts are great, but wouldn't you rather write Elixir?
Also, you dont have to care about things like making a file executable. `Committee` will handle that for you :)
> Difficult to share with team
`Committee` exposes an easy mix task to install itself.
To share it with your team, all you have to do is to put `mix committee.install` in one of your onboarding script. **It's a one-time installation**, and from then on, any updates you make to `commit.exs` (`Committee`'s configuration file) will become **immediately available to your team mates**.
*No fuss, no muss.*
### What are some alternatives?
#### Husky
Husky is great, it's a popular git hook manager in JavaScript-land. It is not limited to just JS, it also works for any other languages, including Elixir.
The only downside is that you'd need to set up `package.json` to include the `husky` dependency. I figured not every Elixir project would have `package.json` (for example when developing a library), hence `Committee`.
Husky is a much more battle-proven solution, and works for most scenarios (especially if you already have a `package.json`), so definitely go for that if suits your use case.
#### Lefthook
A project from Evil Martian. This project is really interesting, it is written in Go, works for any language by using a language-agnostic `.yml` config file. I like the idea that it's taking.
I was really contemplating using Lefthook, but I decided to take up a sort of challenge to come up with an Elixir-like hook manager, so well here we are..
#### Other Elixir Alternatives
There are few more Elixir-centric packages, like:
- [husky-elixir](https://github.com/spencerdcarlson/husky-elixir) (I'm not sure if it's officially affliated with the JavaScript library)
- [elixir_git_hooks](https://github.com/qgadrian/elixir_git_hooks)
- [elixir-pre-commit](https://github.com/dwyl/elixir-pre-commit)
They all look great, but all hinges on using `config.exs` to do configuration <sup>*Now that I'm writing this out, I realised I'm the outlier here..*</sup>, which works, but I decided to be a little bit more creative, and take this Elixir thing a step further.
Thus born `Committee`, which allows you to write any Elixir code in a `commit.exs` file, because why not?
> <sup>1</sup> This is not always the case, you can change the [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) to run your code with other shell/languages, such as `ruby`.
---
## Contributions
Contributions are very welcomed, but please first [open an issue](https://github.com/edisonywh/committee/issues/new) so we can align and discuss before any development begins.
## License
View [License](https://github.com/edisonywh/committee/blob/master/LICENSE)