Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add auto install feature for pre-commit plugin #12349

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 47 additions & 0 deletions plugins/pre-commit/README.md
Expand Up @@ -17,3 +17,50 @@ plugins=(... pre-commit)
| prcr | `pre-commit run` | The `pre-commit run` command |
| prcra | `pre-commit run --all-files` | Run pre-commit hooks on all files |
| prcrf | `pre-commit run --files` | Run pre-commit hooks on a given list of files |


## Auto install `pre-commit` hook

This plugin can auto install the defined pre-commit hooks from a `.pre-commit-config.yaml`, if it detects that file in your current working dir.

## Settings

#### ZSH_PRE_COMMIT_AUTO_INSTALL

Set `ZSH_PRE_COMMIT_AUTO_INSTALL` to control auto install.

- `prompt` (default) will prompt on a per-directory basis
- `off` will turn the feature off
- any other setting will auto install without prompting.

```zsh
# in ~/.zshrc, before Oh My Zsh is sourced:
ZSH_PRE_COMMIT_AUTO_INSTALL=prompt|off|anything_else_is_on
```

#### ZSH_PRE_COMMIT_CONFIG_FILE

The plugin will default to use `.pre-commit-config.yaml`.

You can override this with the variable `$ZSH_PRE_COMMIT_CONFIG_FILE`, like so:

```zsh
# in ~/.zshrc, before Oh My Zsh is sourced:
ZSH_PRE_COMMIT_CONFIG_FILE=.my-custom-pre-commit-config.yaml
```

#### ZSH_PRE_COMMIT_INSTALLED_LIST

The default behavior of the plugin is to prompt for installation. It will also remember it did so, which will be cached in a list to be defined by: `$ZSH_PRE_COMMIT_INSTALLED_LIST`.

The details for the three options are:
- **Y**es: install and write the current dir into the list.
- **A**sk again for this directory: don't do anything now.
- **N**ever ask again for this directory: don't install, but write the current dir into the list.

By default, this list will be here `${ZSH_CACHE_DIR:-$ZSH/cache}/pre-commit-installed.list"`, but you can set the filename of that list to whatever you want:

```zsh
# in ~/.zshrc, before Oh My Zsh is sourced:
ZSH_PRE_COMMIT_INSTALLED_LIST=/path/to/list
```
71 changes: 71 additions & 0 deletions plugins/pre-commit/pre-commit.plugin.zsh
Expand Up @@ -6,3 +6,74 @@ alias prcau='pre-commit autoupdate'
alias prcr='pre-commit run'
alias prcra='pre-commit run --all-files'
alias prcrf='pre-commit run --files'

# Auto install

## Settings

# Filename of the pre-commit file to look for
: ${ZSH_PRE_COMMIT_CONFIG_FILE:=.pre-commit-config.yaml}

# Path to the file containing installed paths
: ${ZSH_PRE_COMMIT_INSTALLED_LIST:="${ZSH_CACHE_DIR:-$ZSH/cache}/pre-commit-installed.list"}

# Default setting for auto install to prompt
: ${ZSH_PRE_COMMIT_AUTO_INSTALL:="prompt"}

## Functions

autoload -U add-zsh-hook
if [[ "$ZSH_PRE_COMMIT_AUTO_INSTALL" == "off" ]]; then
add-zsh-hook -d chpwd auto_install_pre_commit
return
fi

auto_install_pre_commit() {
if [[ ! -f "$ZSH_PRE_COMMIT_CONFIG_FILE" ]]; then
return
fi

local dirpath="${PWD:A}"

# early return if already installed
if command grep -Fx -q "$dirpath" "$ZSH_PRE_COMMIT_INSTALLED_LIST" &>/dev/null; then
return
fi

if [[ "$ZSH_PRE_COMMIT_AUTO_INSTALL" == "prompt" ]]; then
local confirmation

touch "$ZSH_PRE_COMMIT_INSTALLED_LIST"

# get cursor column and print new line before prompt if not at line beginning
local column
echo -ne "\e[6n" > /dev/tty
read -t 1 -s -d R column < /dev/tty
column="${column##*\[*;}"
[[ $column -eq 1 ]] || echo

# print same-line prompt and output newline character if necessary
echo -n "pre-commit: found '$ZSH_PRE_COMMIT_CONFIG_FILE' file. Install hooks? ([Y]es/[A]sk again/[N]ever)"
read -k 1 confirmation
[[ "$confirmation" = $'\n' ]] || echo

# check input
case "$confirmation" in
[yY]) ;; # yes
[aA]) return ;; # ask again
[nN]) echo "$dirpath" >> "$ZSH_PRE_COMMIT_INSTALLED_LIST"; return ;; # never ask again
*) return ;; # interpret anything else as ask again
esac
fi

# check if pre-commit is installed
if ! type pre-commit > /dev/null; then
echo "You need to install pre-commit first. https://pre-commit.com/#install can help you out.";
return
fi

pre-commit install && echo "$dirpath" >> "$ZSH_PRE_COMMIT_INSTALLED_LIST"
}

add-zsh-hook chpwd auto_install_pre_commit
auto_install_pre_commit