diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a1bf61f..2c5c0f4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## master (unreleased) +- feature: Allow providing rc file ([PR #392](https://github.com/evilmartians/lefthook/pull/392) by @mrexox) + ## 1.2.3 (2022-11-30) - feature: Expand env variables ([PR #391](https://github.com/evilmartians/lefthook/pull/391) by @mrexox) diff --git a/docs/configuration.md b/docs/configuration.md index 749a078f..a7d98b81 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -7,6 +7,7 @@ - [`skip_output`](#skip_output) - [`source_dir`](#source_dir) - [`source_dir_local`](#source_dir_local) + - [`rc`](#rc) - [`remote` (Beta :test_tube:)](#remote) - [`git_url`](#git_url) - [`ref`](#ref) @@ -140,6 +141,65 @@ Change a directory for *local* script files (not stored in VCS). This option is useful if you have a `lefthook-local.yml` config file and want to reference different scripts there. +### `rc` + +Provide an [**rc**](https://www.baeldung.com/linux/rc-files) file, which is actually a simple `sh` script. Currently it can be used to set ENV variables that are not accessible from non-shell programs. + +**Example** + +Use cases: + +- You have a GUI program that runs git hooks (e.g., VSCode) +- You reference executables that are accessible only from a tweaked $PATH environment variable (e.g., when using rbenv or nvm) +- Or even if your GUI programm cannot locate the `lefthook` executable :scream: +- Or if you want to use ENV variables that control the executables behavior in `lefthook.yml` + +```bash +# An npm executable which is managed by nvm +$ which npm +/home/user/.nvm/versions/node/v15.14.0/bin/npm +``` + +```yml +# lefthook.yml + +pre-commit: + commands: + lint: + run: npm run eslint {staged_files} +``` + +Provide a tweak to access `npm` executable the same way you do it in your ~/rc + +```yml +# lefthook-local.yml + +# You can choose whatever name you want. +# You can share it between projects where you use lefthook. +# Make sure the path is absolute. +rc: ~/.lefthookrc +``` + +```bash +# ~/.lefthookrc + +# An nvm way + +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +# Or maybe just + +PATH=$PATH:$HOME/.nvm/versions/node/v15.14.0/bin +``` + +```bash +# Make sure you updated git hooks. This is important. +$ lefthook install -f +``` + +Now any program that runs your hooks will have a tweaked PATH environment variable and will be able to get `nvm` :wink: + ## `remote` > :test_tube: This feature is in **Beta** version diff --git a/internal/config/config.go b/internal/config/config.go index 2e6377af..f5131f8d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,6 +12,7 @@ type Config struct { SkipOutput []string `mapstructure:"skip_output"` SourceDir string `mapstructure:"source_dir"` SourceDirLocal string `mapstructure:"source_dir_local"` + Rc string `mapstructure:"rc"` Hooks map[string]*Hook } diff --git a/internal/lefthook/add.go b/internal/lefthook/add.go index bcb05eb2..27211622 100644 --- a/internal/lefthook/add.go +++ b/internal/lefthook/add.go @@ -35,7 +35,7 @@ func (l *Lefthook) Add(args *AddArgs) error { return err } - err = l.addHook(args.Hook) + err = l.addHook(args.Hook, "") if err != nil { return err } diff --git a/internal/lefthook/install.go b/internal/lefthook/install.go index a54da87d..d643385d 100644 --- a/internal/lefthook/install.go +++ b/internal/lefthook/install.go @@ -125,12 +125,12 @@ func (l *Lefthook) createHooksIfNeeded(cfg *config.Config, force bool) error { return err } - if err = l.addHook(hook); err != nil { + if err = l.addHook(hook, cfg.Rc); err != nil { return err } } - if err = l.addHook(config.GhostHookName); err != nil { + if err = l.addHook(config.GhostHookName, cfg.Rc); err != nil { return nil } diff --git a/internal/lefthook/lefthook.go b/internal/lefthook/lefthook.go index d335ab95..fa9ae97b 100644 --- a/internal/lefthook/lefthook.go +++ b/internal/lefthook/lefthook.go @@ -113,9 +113,9 @@ func (l *Lefthook) cleanHook(hook string, force bool) error { } // Creates a hook file using hook template. -func (l *Lefthook) addHook(hook string) error { +func (l *Lefthook) addHook(hook, rc string) error { hookPath := filepath.Join(l.repo.HooksPath, hook) return afero.WriteFile( - l.Fs, hookPath, templates.Hook(hook), hookFileMode, + l.Fs, hookPath, templates.Hook(hook, rc), hookFileMode, ) } diff --git a/internal/templates/hook.tmpl b/internal/templates/hook.tmpl index a7f603ab..ad9c3e11 100644 --- a/internal/templates/hook.tmpl +++ b/internal/templates/hook.tmpl @@ -4,6 +4,12 @@ if [ "$LEFTHOOK" = "0" ]; then exit 0 fi +{{- if .Rc}} +{{/* Load rc file and export all ENV vars defined in it */}} +set -a +[ -f '{{.Rc}}' ] && source '{{.Rc}}' +{{- end}} + call_lefthook() { dir="$(git rev-parse --show-toplevel)" diff --git a/internal/templates/templates.go b/internal/templates/templates.go index 567b0933..0a1112db 100644 --- a/internal/templates/templates.go +++ b/internal/templates/templates.go @@ -16,14 +16,16 @@ var templatesFS embed.FS type hookTmplData struct { HookName string Extension string + Rc string } -func Hook(hookName string) []byte { +func Hook(hookName, rc string) []byte { buf := &bytes.Buffer{} t := template.Must(template.ParseFS(templatesFS, "hook.tmpl")) err := t.Execute(buf, hookTmplData{ HookName: hookName, Extension: getExtension(), + Rc: rc, }) if err != nil { panic(err)