fork-dev / Tracker

Bug and issue tracker for Fork for Mac
509 stars 12 forks source link

Incorrect $PATH variable in pre-commit exec environment #1227

Open SachinShekhar opened 3 years ago

SachinShekhar commented 3 years ago

MacOS 11.1 update broke Fork's exec environment.

echo $PATH in pre-commit hook displays different outputs in Fork & terminals.

Fork: /usr/local/Cellar/git/2.28.0/libexec/git-core:/Applications/Fork.app/Contents/Resources/git-instance/git-lfs:/Applications/Fork.app/Contents/Resources/gitflow-avh:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Any Terminal: /Users/Sachin/.avn/bin:/Users/Sachin/.nvm/versions/node/v14.12.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/MacGPG2/bin:/Library/Apple/usr/bin

So, naturally, lots of commands fail to run with Command not found error.

DanPristupov commented 3 years ago

echo $PATH in pre-commit hook displays different outputs in Fork & terminals.

This is correct behavior, until I'm missing something important. Why do you think macOS update is involved?

Any Terminal

Terminal process PATH is not related to Fork in any way. Fork doesn't know about other processes (including terminal).

If you want Fork to have ENV as Terminal, start it from Terminal (using open -a Fork . command)

SachinShekhar commented 3 years ago

Fork obviously can't read PATH exposed to other processes, but doesn't it have to load a common profile for its shell exec environment? /etc/paths, ~/.zshrc, ~/.bashrc etc files are going to be common for all shell processes.

What shell does the Fork use or does it even use a shell at all? I expected the $PATH to be same because I thought Fork uses an existing shell with all of its default configuration.

I started getting Command not found error only after the MacOS update. Previously, everything was working correctly (think how it got PATH from .zshrc or .bashrc).

DanPristupov commented 3 years ago

What shell does the Fork use or does it even use a shell at all?

No, Fork doesn't use shell.

I started getting Command not found error only after the MacOS update. Previously, everything was working correctly (think how it got PATH from .zshrc or .bashrc).

I guess, previously you had node in /usr/local/bin and update changed this.

SachinShekhar commented 3 years ago

I guess, previously you had node in /usr/local/bin and update changed this.

I don't think so. I use nvm to manage node.

But, in any case, Fork should also add PATH from standard shell profiles like .zshrc (maybe, after getting permission from Preferences). Consider it as a feature request 🚀.

DanPristupov commented 3 years ago

But, in any case, Fork should also add PATH from standard shell profiles

I think reading other application's config is just wrong. Also, PATH is not enough. We also need environment variables and aliases.

like .zshrc

The format of this file is not trivial. And BTW, I don't have this file on my computer.

SachinShekhar commented 3 years ago

The format of this file is not trivial.

.zshrc and .bashrc are very famous and their formats are open source. I am sure there are libs in existence which can extract information from them.

I think reading other application's config is just wrong. Also, PATH is not enough. We also need environment variables and aliases.

We're talking about famous shell configs here. At the very least, provide a way to edit those variables through Preferences.

ls-sam-leatherdale commented 3 years ago

After experiencing similar issues to @SachinShekhar, here are my findings so far: (btw I am running macOS 11.0.1)

~/.zshrc and ~/.bashrc are loaded for interactive shells, according to https://unix.stackexchange.com/questions/71253/what-should-shouldnt-go-in-zshenv-zshrc-zlogin-zprofile-zlogout

However, zsh also supports ~/.zshenv for non-interactive shells, which bash doesn't appear to support.

I tested the different configs in Fork, Sourcetree, and Tower. Loading nvm in ~/.zshrc and then running a node command in the pre-commit didn't work in any of the clients.

However, loading nvm in ~/.zshenv did work in Sourcetree, but not in Tower or Fork.

I think Fork should support ~/.zshenv as it is designed for situations like this (invoking a non-interactive shell). I also agree that it would be great to specify a shell config in Preferences for people who want to keep using bash.

@DanPristupov Regarding reading the format of this file, you don't have to do any special reading. These files are simply a shell script that should be executed with that particular shell.

DanPristupov commented 3 years ago

However, zsh also supports ~/.zshenv for non-interactive shells, which bash doesn't appear to support.

Are you sue .nvm uses ~/.zshenv? According to website it doesn't:

correct profile file (~/.bash_profile, ~/.zshrc, ~/.profile, or ~/.bashrc).

@saml-kounta

Regarding reading the format of this file, you don't have to do any special reading. These files are simply a shell script that should be executed with that particular shell.

Fork doesn't use or run any shell.

These files are simply a shell script that should be executed with that particular shell.

I'm not 100% sure what you mean, but in this case the ENV will be used within that shell and not in Fork. Or, should that shell start the Fork process after that? Then it's exactly what we have right now already.

ls-sam-leatherdale commented 3 years ago

However, zsh also supports ~/.zshenv for non-interactive shells, which bash doesn't appear to support.

Are you sue .nvm uses ~/.zshenv? According to website it doesn't:

correct profile file (~/.bash_profile, ~/.zshrc, ~/.profile, or ~/.bashrc).

You can put those commands wherever you like. It makes more sense to put them in zshenv because node should be available from all shells, not just interactive shells.

Since .zshenv is always sourced, it often contains exported variables that should be available to other programs. For example, $PATH, $EDITOR, and $PAGER are often set in .zshenv.

@saml-kounta

Regarding reading the format of this file, you don't have to do any special reading. These files are simply a shell script that should be executed with that particular shell.

Fork doesn't use or run any shell.

I'm very confused by this. Fork executes the pre-commit script and shows you the output, so it is executing a shell one way or another, even if not directly. Are you just running git commit and then displaying the output?

These files are simply a shell script that should be executed with that particular shell.

I'm not 100% sure what you mean, but in this case the ENV will be used within that shell and not in Fork. Or, should that shell start the Fork process after that? Then it's exactly what we have right now already.

So the way I would see it working is Fork would spawn a shell process, which runs the zshenv file, then runs the appropriate git command.

What I don't understand is why running zsh from within Fork, whether called directly or via git pre commit hookz, is not the same as running a shell from within any other app, like JetBrains WebStorm, VSCode, etc. When you spawn git which subsequently runs the hook in zsh, it is inheriting different env vars than a regular terminal shell, like the OP shows, the path has Fork specific stuff in it. Maybe that is caused by a macOS change.

DanPristupov commented 3 years ago

Are you sue .nvm uses ~/.zshenv? According to website it doesn't:

You can put those commands wherever you like.

I'm just saying that handling ~/.zshenv as you proposed is not a solution because nvm doesn't use it.

I'm very confused by this. Fork executes the pre-commit script and shows you the output, so it is executing a shell one way or another, even if not directly.

Fork doesn't execute hooks. Git does.

Are you just running git commit and then displaying the output?

Yes, basically we just run git commands and show the output.

So the way I would see it working is Fork would spawn a shell process, which runs the zshenv file

It would also bring a massive performance overhead. But the main reason is that Fork doesn't need a shell process.

why running zsh from within Fork, whether called directly or via git pre commit hookz, is not the same as running a shell from within any other app, like JetBrains WebStorm, VSCode

I don't have an answer, but may be because hooks use #!/bin/sh by default which is bash, not zsh.

SachinShekhar commented 3 years ago

@saml-kounta There's no reason to think about ~/.zshenv (I don't even have that file). If a child process is spawned with zsh, it'll automatically use ~/.zshrc.

@DanPristupov

It would also bring a massive performance overhead.

Only git commit requires custom exec environment, so there's no need to rewrite anything else. Only when commit button is pressed (and, user has opted for custom shell through Preferences), spawn a child process with custom shell to run the command. Someone who is willing to run git hooks (which are already heavy) can tolerate performance penalty of a heavy process launch (especially when it makes the hooks work).

For good experience, you can suggest users who aren't using custom shell to enable it in Preferences upon finding Command not found error.

ls-sam-leatherdale commented 3 years ago

@SachinShekhar ~/.zshenv is actually more suitable than ~/.zshrc in this scenario, as this StackExchange article clearly states that

Since .zshenv is always sourced, it often contains exported variables that should be available to other programs. For example, $PATH .zshrc is for interactive shell configuration.

Either way, I decided to have a look at how other projects have handled this issue: https://github.com/ghooks-org/ghooks/issues/18 https://github.com/observing/pre-commit/issues/56 https://github.com/nvm-sh/nvm/issues/688

Tower even has a dedicated support article for it: https://www.git-tower.com/help/guides/faq-and-tips/faq/hook-scripts/mac

It seems like the overall consensus is that the best way to handle it is just to source your ~/.zshrc or whatever you want to use from inside your pre-commit hook script.

However, in the Tower article above, they also offer the option of customising the $PATH and other environment variables. Maybe that would be a suitable compromise as well?

SachinShekhar commented 3 years ago

A temporary workaround which works for me is creating symlinks in /usr/local/ (won't work if something other than $PATH is involved in breaking the environment). GNU Stow can be used if there are large number of binaries involved.

ivanggq commented 3 years ago

I started experiencing the same issue with Fork, after I updated from Catalina to Big Sur.

I compared how Fork and VS Code are started on my machine when I just double-click from Finder (see below for full cmd line). You will notice that the VS Code receives a lot more env vars, which are the normal env vars when I open my Terminal, with default shell of zsh.

The PATH env var is different too:

PATH passed to Fork: PATH=/usr/bin:/bin:/usr/sbin:/sbin PATH passed VS Code: PATH=/Users/ivang/.volta/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin

I think the PATH that Fork receives is a very default one from /etc/paths, while VS Code receives the env vars from my profile/shell - in general things I have set up in ~.

I am not sure why this happens, but I would focus on why Big Sur's Finder doesn't treat Fork the same as VS Code. Is it an entitlement in Info.plist, or something else?

(open -a Fork . works, but this is not solving the original issue).

Fork: /Applications/Fork.app/Contents/MacOS/Fork USER=ivang __CFBundleIdentifier=com.DanPristupov.Fork COMMAND_MODE=unix2003 LOGNAME=ivang PATH=/usr/bin:/bin:/usr/sbin:/sbin SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.fd34DZJ5gX/Listeners SHELL=/bin/zsh HOME=/Users/ivang __CF_USER_TEXT_ENCODING=0x68B3B887:0x0:0x0 TMPDIR=/var/folders/d2/svj1s5gn6_v88skdzfjwdmbdmb7f47/T/ XPC_SERVICE_NAME=application.com.DanPristupov.Fork.39758057.39758452 XPC_FLAGS=1 VS Code: /Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Renderer).app/Contents/MacOS/Code Helper (Renderer) /Applications/Visual Studio Code.app/Contents/Resources/app/out/bootstrap-fork --type=searchService ELECTRON_RUN_AS_NODE=1 USER=ivang __CFBundleIdentifier=com.microsoft.VSCode COMMAND_MODE=unix2003 LOGNAME=ivang PATH=/Users/ivang/.volta/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.fd34DZJ5gX/Listeners SHELL=/bin/zsh HOME=/Users/ivang __CF_USER_TEXT_ENCODING=0x68B3B887:0x0:0x0 TMPDIR=/var/folders/d2/svj1s5gn6_v88skdzfjwdmbdmb7f47/T/ XPC_SERVICE_NAME=application.com.microsoft.VSCode.42545926.42545932 XPC_FLAGS=0x0 ORIGINAL_XDG_CURRENT_DESKTOP=undefined VSCODE_NLS_CONFIG={"locale":"en-us","availableLanguages":{},"_languagePackSupport":true} VSCODE_NODE_CACHED_DATA_DIR=/Users/ivang/Library/Application Support/Code/CachedData/622cb03f7e070a9670c94bae1a45d78d7181fbd4 VSCODE_IPC_HOOK=/Users/ivang/Library/Application Support/Code/1.53.2-main.sock VSCODE_PID=6621 SHLVL=0 PWD=/ OLDPWD=/ VOLTA_HOME=/Users/ivang/.volta _=/Applications/Visual Studio Code.app/Contents/MacOS/Electron VSCODE_PARENT_PID=6741 VSCODE_AMD_ENTRYPOINT=vs/workbench/services/search/node/searchApp VSCODE_PIPE_LOGGING=true VSCODE_VERBOSE_LOGGING=false NODE_CHANNEL_FD=3 NODE_CHANNEL_SERIALIZATION_MODE=json

Edit: I just found that the first process of VS Code is started similarly to Fork: /Applications/Visual Studio Code.app/Contents/MacOS/Electron USER=ivang __CFBundleIdentifier=com.microsoft.VSCode COMMAND_MODE=unix2003 LOGNAME=ivang PATH=/usr/bin:/bin:/usr/sbin:/sbin SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.fd34DZJ5gX/Listeners SHELL=/bin/zsh HOME=/Users/ivang __CF_USER_TEXT_ENCODING=0x68B3B887:0x0:0x0 TMPDIR=/var/folders/d2/svj1s5gn6_v88skdzfjwdmbdmb7f47/T/ XPC_SERVICE_NAME=application.com.microsoft.VSCode.42545926.42545932 XPC_FLAGS=1 So it seems VS Code, being an Electron application, is passing a different environment to the new processes it launches.

SachinShekhar commented 3 years ago

So it seems VS Code, being an Electron application, is passing a different environment to the new processes it launches.

That's a clever way to do it. I suggested a similar thing for when commit button is pressed. No need to bloat the entire app with unnecessary environment.

ospfranco commented 3 years ago

Although not ideal, adding symlinks to the local bin path is working.

In my case (since I'm using Volta), this works (replace 'osp' with your user name):

ln -s /Users/osp/.volta/bin/yarn /usr/local/bin
jessypouliot98 commented 2 years ago

Although not ideal, adding symlinks to the local bin path is working.

In my case (since I'm using Volta), this works (replace 'osp' with your user name):

ln -s /Users/osp/.volta/bin/yarn /usr/local/bin

This fix does work, but here's how I would suggest doing this (easier to work with if you have to change node versions).

I have added to my .zshrc (works with .bash_profile, .bashrc, etc.):

alias nvm:link="nvm:link:node && nvm:link:npm && nvm:link:npx && nvm:link:yarn"
alias nvm:link:node="echo Linking node && rm -rf /usr/local/bin/node && ln -s $NVM_BIN/node /usr/local/bin/node"
alias nvm:link:npm="echo Linking npm && rm -rf /usr/local/bin/npm && ln -s $NVM_BIN/npm /usr/local/bin/npm"
alias nvm:link:npx="echo Linking npx && rm -rf /usr/local/bin/npx && ln -s $NVM_BIN/npm /usr/local/bin/npx"
alias nvm:link:yarn="echo Linking yarn && rm -rf /usr/local/bin/yarn && ln -s $NVM_BIN/yarn /usr/local/bin/yarn"

Then run nvm:link dont forget to source or reload your terminal

$NVM_BIN is equal to wherever nvm binaries are installed I dont know if you always get that global env variable, but it is automatically setup on my computer with nvm installed from homebrew

srichter commented 2 years ago

I used the trick from this answer to run my .zshenv when starting Fork (it will break auto-update, however):

#!/bin/sh

. ~/.zshenv

open -a "`dirname \"$0\"`/Fork" --args "$@"

Another +1 for built-in support for managing $PATH within Fork

Przeblysk commented 2 years ago

add .huskyrc

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
amowu commented 2 years ago

add .huskyrc

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

In my case, I install Node via nvm, and I use Node v16 that built-in Yarn, so I have not global Yarn, and Fork can not found Yarn.

My solution is upgrade husky to latest version, its structure is:

.husky/
  _/
    .gitignore
    husky.sh 👈 git will ignore this
  commit-msg
  pre-commit

Paste nvm code into husky.sh:

#!/bin/sh

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

...

And my Fork's husky work fine.

fshafiee commented 2 years ago

I think reading other application's config is just wrong. Also, PATH is not enough. We also need environment variables and aliases.

@DanPristupov, then perhaps you could provide a way so that we could configure fork environment separately (e.g a ~/.forkrc file).

pvinis commented 2 years ago

opening up fork from the terminal used to work and it had the right env. this doesn't work anymore. why?

DanPristupov commented 2 years ago

@pvinis try to find out more using echo $PATH in the pre-commit hook

vin047 commented 2 years ago

I have a pretty complicated SSH config file which utilises environment variables for some keywords like IdentityAgent. The variables are set by a bash script thats called by my .bash_profile. I agree that Fork shouldn't just inherit environment variables from a users shell. But it'd still be great if Fork had a way to inject custom environment variables via a script, like a .forkrc file as suggested earlier: https://github.com/fork-dev/Tracker/issues/1227#issuecomment-1137339490. Then I could just source my existing bash script.

Workaround

In the meantime, for anyone who wishes to inject their own environment variables but doesn't want to call Fork from the command line or wrap it around a script – I found out that setting environment variables via launchctl setenv KEY VALUE will make them visible to all processes on macOS, including GUI apps like Fork. To make the changes persist over reboots, I created a script to set the variables, then run the script with launchd.

  1. Create script to set variables:
    
    #!/usr/bin/env bash

launchctl setenv VAR1 myvar1 launchctl setenv VAR2 myvar2 launchctl setenv VAR3 myvar3

Save to whatever path, e.g. `~/env-vars.sh`

2. Create a `launchd` job to run the script when macOS starts:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>local.env-vars</string>
    <key>EnableGlobbing</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>~/env-vars.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

Save to ~/Library/LaunchAgents/local.env-vars.plist

  1. Load and start the job: launchctl load ~/Library/LaunchAgents/local.env-vars.plist

This makes the environment variables visible to Fork and any processes that Fork initiates (such as SSH, which was my use case for wanting custom environment variables). Works on macOS Big Sur 11.6.

Note: This also makes the variables available to other GUI apps too, so you can use this to set custom environment variables for other git GUI clients, IDEs etc. In fact it even sets the environment variables for the shell too. Remember not to use this to set any sensitive info though as the variables will be visible to ALL processes on macOS.

nicekiwi commented 2 years ago

opening up fork from the terminal used to work and it had the right env. this doesn't work anymore. why?

it works for me :)

nicekiwi commented 2 years ago

My solution was to simply use the command @DanPristupov suggested at the start in a Mac Shortcut to inject PATH or ENV vars and open fork from shell.

Shortcut command:

. ~/.forkrc
open -a Fork .

~/.forkrc

# Add any other $PATH or ENV logic here
export NVM_DIR="$HOME/.nvm"
  [ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"  # This loads nvm

image

Then just call the shortcut from spotlight or whatever other prefered method. It can even show in launchpad. :)

I dont recommend loading the entire .zshrc file in the shortcut as it adds a short delay to startup. Just the essentials adds no noticable delay.

image

thihathit commented 1 year ago

All of the workarounds like injecting PATH before invoking open -a Fork would be incorrect when the project use version management systems.

In case of NodeJS, nvm or fnm would only try to pick up the default node version instead of project-scoped version from config like .node-version or .nvmrc.

So the problem is nvm,fnm, & node are additional layers that's not related to git. Which is understandable that GUI tools doesn't handle them natively.

But what if we have an additional layer before git-hook / git is being invoked, all within the same processing context.

I think, a plugin system might be able to solve this. A system that expose before event upon invoking pre-commit or any other git commands... Maybe let's just call it fork's-before-pre-commit event. Which executes all within the same processing context, so that PATH can be still passed down onto the script level.

Example:

1. Fork's customizable layer

# For NVM
if [ -x "$(command -v nvm)" ]; then
    # point to nvm's directory
    source ~/.nvm/nvm.sh

    # Auto select project's node version
    nvm use
fi

# For FNM
if [ -x "$(command -v fnm)" ]; then
    # fnm doesn't need directory pointing when installed via brew
    # Auto select project's node version
    eval "$(fnm env --use-on-cd)"
fi

2. pre-commit hook

node -v

Such a layer might also benefits to other uses as well, not limiting to just NodeJS and people can get creative with it.

I guess it's gonna be really tricky to implement it 🥹😅

SachinShekhar commented 1 year ago

This should be implemented by git.

markpokornycos commented 1 year ago

This bit me at work today. The repo we use has a custom integration to run hooks on different git events. I got it all setup and running in the Terminal with zsh. And then with a small change to zshrc it worked fine in the IDE (Android Studio in this case). But not for Fork. I would love to see some way to configure Fork with an environment you can provision.

nsrosenqvist commented 1 year ago

+1 Even just an interface to manually set environment variables Fork should use would be enough.

nicekiwi commented 1 year ago

All of the workarounds like injecting PATH before invoking open -a Fork would be incorrect when the project use version management systems.

What do you mean?

Injecting nvm into path before using open -a Fork . works fine with Git hooks. They use the correct node version etc.

thihathit commented 1 year ago

All of the workarounds like injecting PATH before invoking open -a Fork would be incorrect when the project use version management systems.

What do you mean?

Injecting nvm into path before using open -a Fork . works fine with Git hooks. They use the correct node version etc.

suppose your project uses node 16, your nvm uses 18 by default, hook will run using 18.

thihathit commented 1 year ago

https://github.com/fork-dev/Tracker/assets/30023628/02e84ea9-08fb-4a81-9f55-8cd869d739fa

@nicekiwi.

nicekiwi commented 1 year ago

@thihathit possibly related? https://github.com/jorgebucaran/nvm.fish/issues/210

However, this issue would affect normal traversing in the terminal too, another option would be to add a global source command to a config, e.g. if you use husky, adding the following to ~/.huskyrc will load nvm and run nvm use before the hooks run.

export NVM_DIR="$HOME/.nvm"
  [ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"  # This loads nvm
  [ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"  # This loads nvm bash_completion

nvm use

Of course, you could modify it to check for a .nvmrc file first, the same for the ENV var. In the video below, I call node -v before and after nvm use (and again in the pre-commit file i forgot to remove)

https://github.com/fork-dev/Tracker/assets/738975/078a072e-faff-43db-9833-9be90c778cde

This actually negates the need to modify the Fork start-up at all.

thihathit commented 1 year ago

@nicekiwi, that is a different approach actually. And it is working because you're loading nvm inside the pre-commit. PATHS aren't injected via fork. ~/.huskyrc isn't part of the githooks it's just a workaround API made to solve these kinds of situations, which means all the other hook management tools won't work unless they provide the same API.

Actually if we're going to do something like that, you can just source your primary terminal profile, e.g source ~/.zshrc. This will allows your pre-commit to behave the same with terminal. This is what I'm using currently.

Nevertheless, someone has to provide an extra layer to resolve this, either fork or githook manager like husky. Hence the reason why I suggested it'd be cool if fork could do some kind of shell-based plugin layer. Who knows maybe we can even create community plug-ins around it. haha

jonrh commented 1 year ago

Ran into this error as well when committing for the first time while trying out Fork. Working on a project that uses automatic code formatting with Prettier, Husky commit hooks, and lint-staged. Not an uncommon setup in JS/TS frontend projects. Node installations managed by asdf using ZSH & Git installation method (shims sourced in ~./zshrc).

One way to get Fork working with Husky, lint-staged, and asdf was to source asdf in ~/.huskyrc as previously suggested:

# File: ~/.huskyrc
. "$HOME/.asdf/asdf.sh"

The above assumes asdf installed via ZSH & Git. The content is different for different asdf installation methods and/or Node version managers like nvm.

The error was quite surprising because committing worked as expected using git, GitKraken & WebStorm. Assumed that Fork would use the default operating system shell and the environment that it configures. Maybe Fork could display a custom error message with a link to a troubleshooting page if a command is missing?

Click to view text version of error Git Error. An unexpected error occurred while performing the git request. Error details: $ git commit --file=/var/folders/hd/xxx/T/yyy .husky/pre-commit: line 4: npx: command not found husky - pre-commit hook exited with code 127 (error) husky - command not found in PATH=/Applications/Fork.app/Contents/Resources/git-instance/libexec/git-core:/Applications/Fork.app/Contents/Resources/git-instance/git-lfs:/Applications/Fork.app/Contents/Resources/gitflow-avh:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
Screenshot 2023-06-28 at 12 39 50
andymac4182 commented 1 year ago

Thanks @jonrh I was able to use this to get asdf working with Fork!! :) Massive thanks for that.

Here is the command I ran to fix mine. This is for homebrew installed asdf

echo ". /opt/homebrew/opt/asdf/libexec/asdf.sh" > ~/.huskyrc
quartz-fm commented 1 year ago

Had a similar issue with pre-commit hooks. Using the ~/.huskyrc as mentioned solved them. I think this is the cleanest workaround.

RafaelPlantard commented 1 year ago

Does anybody know how to solve that for lefthook integration?

image
DanPristupov commented 1 year ago

@RafaelPlantard did you try to start Fork from the command line? open -a Fork .? (https://github.com/fork-dev/Tracker/issues/1227#issuecomment-748522844)

thihathit commented 1 year ago

Does anybody know how to solve that for lefthook integration?

try above command first. it will work unless you're using runtime version manager like nvm/fnm. the proper fix would need to provide from either githook tool(lefthook in your case) or via Fork(via plugin-api/customization layer).

In case you're using runtime version manager, invoke it inside your pre-commit hook before any of your node commands. This will give you correct version of your runtime. you can also try with husky githook & do it from .huskyrc, it'll also give you correct version.

RafaelPlantard commented 12 months ago

@RafaelPlantard did you try to start Fork from the command line? open -a Fork .? (https://github.com/fork-dev/Tracker/issues/1227#issuecomment-748522844)

it worked your solution.

ferologics commented 11 months ago

It'd be nice if Fork could read the PATH before running git hooks / always on startup. Running open -a Fork . after every reboot is becoming a bit of a pain. Any suggestion on how this could easily be implemented @DanPristupov?

ospfranco commented 7 months ago

Still running into this in 2024. Besides my previous answer (symbolic link to /bin folder, which by the way, also fixes some XCode errors if you are using React Native or some other framework that uses node), the solutions by hook managers like Husky or LeftHook is an rc file.

Here is the documentation for LeftHook RC File

kriscoleman commented 7 months ago

my team just experienced this problem with our pre-commit hooks for commitlint. we moved to gitkraken for now

zoharlevin commented 5 months ago

why is there still no easy way to configure PATH for fork?

eJuke commented 4 months ago

Same issue here

I understand your concerns about parsing bash/zsh configuration files, cause it can really lead to unexpected outcome and might be hard to implement. But why can't we read PATH content from system-wide files like /etc/paths and /etc/paths.d/* ? Since these files are designed to store PATH data regardless of user shell, can't we use them when constructing Fork's env vars?

Also there's Mac OS internal's utility /usr/libexec/path_helper (comes with every Mac OS version since Leopard) which sole purpose is to help developers with PATH env - hope it might be useful as well

MarximusMaximus commented 4 months ago

The canonical way of injecting env vars to the GUI session is using launchctl (usually called by a on-login LaunchAgent). However, this doesn't handle if a project has a .env file. In that case, and that case only, I'd tentatively suggest that Fork abide by the .env file. ("Tentatively" b/c I haven't sat and thought through every potential problem that could introduce.)

Abiding by the .env file theoretically can have security problems, however, one probably shouldn't be opening potentially malicious repos in a GUI app (that runs git commands behind the scenes, and therefore potentially git auto scripts) without having inspected any auto-running git scripts anyway...

majew7 commented 2 months ago

I was curious if husky had any help documentation on this topic. Apparently, they do/did!

OLD VERSION V3: Local commands (~/.huskyrc) https://www.npmjs.com/package/husky/v/3.0.5#local-commands-huskyrc

image

Husky will source ~/.huskyrc file if it exists before running hook scripts. You can use it, for example, to load a node version manager or run some shell commands before hooks.

LATEST VERSION OF HUSKY: https://typicode.github.io/husky/how-to.html#node-version-managers-and-guis

you might face a command not found error due to PATH environment variable issues.

adroste commented 2 months ago

When using husky and zsh (with oh-my-zsh), my dry solution is:

# ~/.config/husky/init.sh
export PATH=`(zsh -c 'source ~/.zshrc > /dev/null 2>&1 && echo $PATH')`