Comments (6)
It took me a while, but here's a configuration that works with the current dotnet husky install
by basically checking if it is installed or not. It is a bit tricky to get right, though, and I wouldn't expect people to add such complex tasks. Would be better if it could be fixed somehow in dotnet husky install
instead.
The following code does:
- Only runs
dotnet tool restore
anddotnet husky install
on non-Clean targets. That is, it runs onBuild
,Rebuild
,Build Al
l, but not onClean
. This dramatically increases the speed ofClean
on large solutions, asrestore
&dotnet husky install
is a relatively slow set of commands (didn't test which of the two was the biggest contributor). - Still runs
dotnet tool restore
for everyBuild
-like action for each project in the solution. Still thinking of a way around this. - Does not run
dotnet husky install
anymore if it is already installed. This is now merely a config check (though this requiredgit
to be accessible, this may not be ideal, though for agit-hook
you'd expect git to be there ;) ).
It turned out to be a bit tricky to ensure the not running when cleaning bit. Maybe there's a better way, but in the end, the below works. I just dumped it in an EnableHusky.proj
and use <Import Project="EnableHusky.proj" />
in each project file.
<!--
Prevent running Husky-Install when Target=Clean.
Must run before 'BeforeClean' (just before 'Clean' is not correct and will execute Husky anyway.)
-->
<Target Name="NoHuskyCheckOnClean" BeforeTargets="BeforeClean">
<CreateProperty Value="1">
<Output TaskParameter="Value" PropertyName="SkipHuskyCheck" />
</CreateProperty>
</Target>
<!--
This checks whether Husky is already installed, then installs it, if necessary.
-->
<Target Name="CheckAndInstallHusky" BeforeTargets="Restore;CollectPackageReferences" Condition="'$(SkipHuskyCheck)' != '1'">
<Exec Command="git config --local --default "" --get core.hookspath" ConsoleToMSBuild="true" StandardOutputImportance="Low">
<Output TaskParameter="ConsoleOutput" PropertyName="HuskyHookLocation" />
</Exec>
<CreateProperty Value="true" Condition="'$(HuskyHookLocation)'=='.husky'">
<Output TaskParameter="Value" PropertyName="HuskyAlreadyInstalled" />
</CreateProperty>
<!-- restore dotnet tools -->
<Exec Command="dotnet tool restore" StandardOutputImportance="Low" StandardErrorImportance="High" />
<Message Condition="'$(HuskyAlreadyInstalled)'=='true'" Text="Husky installation skipped: already installed" Importance="high" />
<!-- call husky installer conditionally -->
<CallTarget Targets="InstallHusky" Condition="'$(HuskyAlreadyInstalled)'!='true'" />
</Target>
<!-- The actual Husky Install target, dependently called from CheckAndInstallHusky -->
<Target Name="InstallHusky">
<Message Text="Installing Husky" Importance="high" />
<Exec Condition="'$(HuskyHookLocation)'!='.husky'" Command="dotnet husky install" StandardOutputImportance="Low" StandardErrorImportance="High" WorkingDirectory="..\.." />
</Target>
from husky.net.
Lol, meanwhile you've been fixing this on your end! If you want me to test something, let me know (though it's past midnight here, may be tomorrow).
from husky.net.
To answer my own question, it turns out that Target Batching
works. With your mutex (which prevents problems when run in parallel) and the Outputs
vs Inputs
behavior (where MSbuild diligently tests whether source has been updated), this indeed prevents the execution of the tasks.
Note that the current code still prevents unnecessary running of dotnet husky install
if it is already installed. But tbh, the overhead of this is much less now that MSBuild takes care of dirty-flagging the installation (it only runs when the version is updated).
There's now probably some code that's redundant and hopefully a smaller version is possible. I'll soon test with your mutexed version. For posterity, this is the current version (paths may need to be adjusted if people try to use this, i.e. like the path to dotnet-tools.json
):
<Project>
<PropertyGroup>
<CurrentDate>$([System.DateTime]::Now.ToString(o))</CurrentDate>
</PropertyGroup>
<!--
Prevent running Husky-Install when Target=Clean.
Must run before 'BeforeClean' (just before 'Clean' is not correct and will execute Husky anyway.)
-->
<Target Name="NoHuskyCheckOnClean" BeforeTargets="BeforeClean">
<CreateProperty Value="1">
<Output TaskParameter="Value" PropertyName="SkipHuskyCheck" />
</CreateProperty>
</Target>
<!--
This checks whether Husky is already installed, then installs it, if necessary.
-->
<Target Name="CheckAndInstallHusky"
BeforeTargets="Restore;CollectPackageReferences"
Condition="'$(SkipHuskyCheck)' != '1'"
Inputs="$(MSBuildProjectDirectory)\..\..\.config\dotnet-tools.json"
Outputs="$(MSBuildProjectDirectory)\..\..\.config\husky-installed.lock">
<Exec Command="git config --local --default "" --get core.hookspath" ConsoleToMSBuild="true" StandardOutputImportance="Low">
<Output TaskParameter="ConsoleOutput" PropertyName="HuskyHookLocation" />
</Exec>
<CreateProperty Value="true" Condition="'$(HuskyHookLocation)'=='.husky'">
<Output TaskParameter="Value" PropertyName="HuskyAlreadyInstalled" />
</CreateProperty>
<!-- restore dotnet tools -->
<Exec Command="dotnet tool restore" StandardOutputImportance="Low" StandardErrorImportance="High" />
<Message Condition="'$(HuskyAlreadyInstalled)'=='true'" Text="Husky installation skipped: already installed" Importance="high" />
<!-- call husky installer conditionally -->
<CallTarget Targets="InstallHusky" Condition="'$(HuskyAlreadyInstalled)'!='true'" />
<!-- after successful task exec, ensure on next build it is not run again (MSBuild uses Inputs/Outputs compare for that) -->
<WriteLinesToFile File="$(MSBuildProjectDirectory)\..\..\.config\husky-installed.lock"
WriteOnlyWhenDifferent="true"
Overwrite="true"
Lines="$(CurrentDate)"/>
</Target>
<!-- The actual Husky Install target, dependently called from CheckAndInstallHusky -->
<Target Name="InstallHusky">
<Message Text="Installing Husky" Importance="high" />
<Exec Condition="'$(HuskyHookLocation)'!='.husky'" Command="dotnet husky install" StandardOutputImportance="Low" StandardErrorImportance="High" WorkingDirectory="..\.." />
</Target>
</Project>
from husky.net.
Thanks for sharing your configuration, something like this could be an additional advanced feature to the husky attach
command, I'll be happy if you test this and share your final thoughts on another issue that you think is necessary for others facing a similar problem.
Btw, your name reminds me of this brilliant chess player, I assume you're a different Alireza? ♟️
Yeah 😉, there are a lot of Alireza in Iran, but firoozja is originally from the city I'm living now. :) we have at least one thing in common 😅, plus I also like chess but my rating is half of his.
Have a nice day
from husky.net.
Hi @abelbraaksma,
First of all, thank you for the feedback and your great ideas, I really enjoy these kinds of issues 🙏.
On my end, I solved the problem with a global mutex (as you correctly suggested), and you can try it in v0.5.2
.
but you also mentioned another problem which is multiple restore and install that could make builds slow. I usually don't attach husky to all of my projects and a common/shared project usually does the job, also according to my tests the performance overhead of these two commands is really low but if you think there is a better way to handle this or you had any other suggestion for improvement, you're really welcome, we can discuss it in another issue. btw your configuration is really interesting (I may use some of your checking ideas in the next versions) 👏.
Good luck.
from husky.net.
Thanks for the quick fix, it is much appreciated!
On the significance of small things, I did a little experiment:
Here's a timing on my machine of dotnet husky install
. Commands were given without intervening pause (ignore the first timestamp and call):
d:\temp 2:09:03.99>dotnet husky install
Git hooks installed
d:\temp 2:09:10.41>dotnet husky install
Git hooks installed
d:\temp 2:09:11.15>dotnet husky install
Git hooks installed
d:\temp 2:09:11.90>dotnet husky install
Git hooks installed
d:\temp 2:09:12.64>dotnet husky install
Git hooks installed
d:\temp 2:09:13.39>
On my machine that is 4 commands is 13.39 - 10.41 = 2.98s
, or about 0.75s per command. This may be dotnet
overhead, I don't know. But take the Clean
example. I have 12 projects in a solution (it depends, we have many solutions, some smaller, some larger, up to 30-something projects). Cleaning takes about 2-3s (without Husky). With each project having this command as well, it adds 9s, which is significant.
I also timed dotnet tool restore
, which likely depends on the amount of tools. It took 0.5s per command. Altogether, in this example the two together become ~1.25s. Could be worse, but it adds up (and if this is network time, a faster PC won't solve it enough).
I usually don't attach husky to all of my projects and a common/shared project usually does the job
Yes, I thought of that too. But as soon as it is shared, it'll run on each compile. Oh wait, Visual Studio probably won't recompile the dependency, as long as it is a project with output. But that requires something to be compiled, but maybe there's a simpler way with the EnableHusky.proj
approach where you import it everywhere, but it runs only once (like VS does for already compiled projects).
Edit: maybe something like this could be (ab)used for the "run once during solution build" issue: https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-batching?view=vs-2022
Btw, your name reminds me of this brilliant chess player, Alireza Firouzja. I assume you're a different Alireza? ♟️
from husky.net.
Related Issues (20)
- not working on repos that haven't run dotnet husky install HOT 2
- No hooks logs in Visual Studio with Husky.Net HOT 3
- Add an option to specify git path HOT 1
- dotnet husky install fails if .git folder is in the parent folder of the #C project HOT 2
- Support .NET 7.0 HOT 1
- Husky exec can't find file or assembly in cache HOT 6
- dotnet husky attach cause unnecessary changes HOT 1
- Doesn't support the dotnet tools (e.g jb) HOT 3
- husky install fails when project is a submodule HOT 9
- bash exit 1 doesn't work HOT 4
- Unexpected parameter(s) error with ${staged} variable HOT 6
- Can not find task-runner.json when running dotnet husky run on Windows HOT 9
- fatal: cannot run .husky/pre-commit: No such file or directory on Mac-os HOT 7
- How to avoid empty commit? HOT 1
- error in dotnet husky install HOT 8
- Chunks tasks can't load csx files in parallel. HOT 2
- commit-lint.csx not working HOT 2
- Husky throws an ArgumentException when I try to commit through Sourcetree HOT 5
- Customize Staged variable separator HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from husky.net.