alirezanet / Husky.Net

Git hooks made easy with Husky.Net internal task runner! 🐢 It brings the dev-dependency concept to the .NET world!
https://alirezanet.github.io/Husky.Net/
MIT License
632 stars 29 forks source link

husky install fails when project is a submodule #69

Closed mike-geiger closed 10 months ago

mike-geiger commented 1 year ago

Version

0.5.4

Details

when running dotnet husky install from the root of my project directory, or as part of automated installation, I get an error message

.git can't be found (see https://alirezanet.github.io/Husky.Net/guide/getting-started)
Git hooks installation failed

Steps to reproduce

  1. create a new git repository
    mkdir new_repo
    cd new_repo
    git init
  2. add existing project with husky as a sub-module
    git submodule add git@github.com:alirezanet/Husky.Net.git
  3. build the submodule to trigger husky installation
    cd Husky.Net
    dotnet build

    you will get the following error

    
    MSBuild version 17.5.0+6f08c67f3 for .NET
    Determining projects to restore...
    .git can't be found (see https://alirezanet.github.io/Husky.Net/guide/getting-started)
    Git hooks installation failed
    D:\source\repos\new_repo\Husky.Net\src\Husky\Husky.csproj(61,5): error MSB3073: The command "dotnet husky install" exit
    ed with code 1.

Build FAILED.

D:\source\repos\new_repo\Husky.Net\src\Husky\Husky.csproj(61,5): error MSB3073: The command "dotnet husky install" exit ed with code 1. 0 Warning(s) 1 Error(s)

Time Elapsed 00:00:03.52

alirezanet commented 1 year ago

Hi @mike-geiger,

Thanks for pointing out the issue with Git submodules, I'm currently exploring possible solutions to add submodule support without affecting existing non-submodule projects.

In the meantime, you can try using Husky.Net in the main project and manually remove the attach commands from submodule projects as a workaround, till I find a proper solution for this.

If you have any ideas or suggestions for solving this problem, I'd love to hear them.

mike-geiger commented 1 year ago

This is just verifying the project root, would using git rev-parse to verify that be sufficient? git rev-parse --path-format=relative --show-toplevel

alirezanet commented 1 year ago

The rev-parse command is being used to check whether the user is installing Husky from the project root directory or from a custom path, as it is necessary to locate Husky and git Hook configurations later. Additionally, it may be possible to check whether the current working directory is inside a submodule, similar to the way it is checked for worktrees. However, due to my time constraints, testing this feature will need to be postponed (if nobody helps πŸ˜‰πŸ˜Š)

https://github.com/alirezanet/Husky.Net/blob/73ac9c47473b71fb772747e81e271b7a0e3fa7b0/src/Husky/Cli/InstallCommand.cs#L59

mike-geiger commented 1 year ago

OK, yes, I think this would work the same as worktrees.

Husky.Net> git rev-parse --git-dir
D:/source/repos/new_repo/.git/modules/Husky.Net
Husky.Net>
Husky.Net> pwd

Path
----
D:\source\repos\new_repo\Husky.Net
image

I'm just trying to figure out if it would be possible to remove this check completely. I don't see the .git directory referenced anywhere else in the application, so if it's just looking for the top-level directory, there are other ways to find it.

alirezanet commented 1 year ago

I'm just trying to figure out if it would be possible to remove this check completely. I don't see the .git directory referenced anywhere else in the application, so if it's just looking for the top-level directory, there are other ways to find it.

Well, one of the things that I wanted to test is removing this condition. honestly, I don't remember exactly why we've added this here, that's why I'm not 100 percent sure by removing it we're not breaking something. If you have time and want to contribute feel free to do the changes you think are necessary, later we can test it together.

Tychus commented 10 months ago

So, ran into this issue today. The way i see it two possibilities. Before failing on the .git can't be found we can check if we're inside a submodule.

if we're in a submodule, we get back the path of the super project we can then:

  1. Use the path returned by git to find the main .git and continue with the install normally.
  2. If we get something in stdout we're in a submodule and we just break off.

Option 1 means that if my submodule already uses husky we just use that and we don't attach husky to anything else. This should be enough assuming the .husky is present in the root super project

Option 2 husky install step is in both the submodule and the super project. we check if we're running the submodule target and just break out and let the super project target do the install.

I believe this should work without breaking existing projects. Will give it a try tomorrow and report back.

Comments ?

alirezanet commented 10 months ago

Option 1 means that if my submodule already uses husky we just use that and we don't attach husky to anything else. This should be enough assuming the .husky is present in the root super project.

what if submodule project also has a different husky configurations in it?

Tychus commented 10 months ago

This turns out to be a lot more complicated than i anticipated. Our use case is pretty simple, but to handle god knows how many possible setups out there...

Example tree

``` . β”œβ”€β”€ .git β”œβ”€β”€ .gitmodules β”œβ”€β”€ .husky β”‚ β”œβ”€β”€ _ β”‚ β”‚Β Β  β”œβ”€β”€ .gitignore β”‚ β”‚Β Β  └── husky.sh β”‚ └── task-runner.json β”œβ”€β”€ Submodule β”‚Β Β  β”œβ”€β”€ .git (this is a file pointing at `../.git/modules/Submodule` which is your usual .git folder) β”‚ β”œβ”€β”€ .husky β”‚ β”‚Β Β  β”œβ”€β”€ _ β”‚ β”‚Β Β  β”‚Β Β  β”œβ”€β”€ .gitignore β”‚ β”‚Β Β  β”‚Β Β  └── husky.sh β”‚ β”‚Β Β  └── task-runner.json β”‚Β Β  β”œβ”€β”€ Submodule.sln β”‚Β Β  └── src └── TestHuskySubmodules β”œβ”€β”€ TestHuskySubmodules └── TestHuskySubmodules.sln ```

Option 1: If we're dealing with a submodule we just exit without doing anything. Options 2: If we're in a submodule we install the hooks from the submodule in the submodule's .git folder (which is pointed at by the .git file (submodules have there .git dir in the super project .git folder under the modules subfolder) Option 3: Same as Option 2 but we also install the hooks in the super project .git (I don't personally see any valid uses for this you only want your submodule hooks to run when doing things on the submodule itself and Option 2 handles that.

Let me know what you think. Should Option 3 be handled ?

PS: i also added a IgnoreWhenSubmodule option to install when set we go with Option 1. This means i will also have to change the attach command so it adds that option when specified. any input on what the best way to do that is welcome

alirezanet commented 10 months ago

Option 3: Same as Option 2 but we also install the hooks in the super project .git (I don't personally see any valid uses for this you only want your submodule hooks to run when doing things on the submodule itself and Option 2 handles that.

I agree, I think user can install husky for super project (if needed) later ... so Option 2 makes more sense.

i also added a IgnoreWhenSubmodule option to install ... Maybe make the option name a little bit simpler like IgnoreSubmodule ... (in the description we can add more details)

Thank you for the effort and I know it is harder than we thought ... especially testing different scenarios takes time.