I have a nuget package with a props file, and in the props file I have these commands:
<Target Name="_myRunCommands" BeforeTargets="Rebuild;Build">
<Message Text="$(MyMessagePrefix) Tools install started" Importance="high" />
<!-- restore will install / restore the packages if missing, but not update them -->
<Exec Command="dotnet tool restore" StandardOutputImportance="High" StandardErrorImportance="High" />
<Exec Command="dotnet tool update husky" StandardOutputImportance="High" StandardErrorImportance="High" />
<Exec Command="dotnet tool update csharpier" StandardOutputImportance="High" StandardErrorImportance="High" />
<Exec Command="dotnet husky install" WorkingDirectory="$(MySolutionDir)" />
</Target>
However, I would like for these commands to only be run ONCE when the solution is opened or changed. Not every time the build is run, or multiple times for the same solution.
QUESTION: Is there a way to run these commands just once when the solution is opened? I looked all through the targets and could find nothing that would work. Does anyone have a solution for this?
CLARIFICATION: I don't care what target I run against, if the target is run multiple times, I would like my target to only execute once.
First note that MSBuild is for specifying build steps. Running a target when a file is opened (by Visual Studio? VSCode? Rider? Notepad?) is outside of MSBuild. But I would suggest that your target is fine as a build step.
Also note that a solution can build projects but projects by design have extremely limited information about the solution. More to the point, you can't inject a target into the solution's build of projects from within a project.
A project may have a ProjectReference
to your package. That ProjectReference
is specific to that project. The .props file in the package will be imported into the project and the _myRunCommands
target will be run. Each project that references the package will run the _myRunCommands
target. This is great for sharing/reusing custom targets but not at all the behavior you are looking for.
There is a mechanism for customizing the solution.
For MySolution.sln
, if there are files named before.MySolution.sln.targets
and/or after.MySolution.sln.targets
, they will be auto-imported and used by the solution. However, this only works for command line builds. When building from Visual Studio these files will be ignored.
(That command line builds and Visual Studio builds have differences is awful but that is a whole other subject.)
If you need parity between cli and VStudio builds, another approach is to create a utility project. Within a given solution build, the utility project, like any project, will be built once.
You can use the Microsoft.Build.NoTargets
Project SDK for the utility project.
Be sure to make the utility project a dependency of projects that need the utility project built first. Dependencies can be set in the solution file. In Visual Studio in the solution explorer, you can right-click on the solution and choose "Project Dependencies".
To limit the _myRunCommands
target of the utility project from building on every solution build, you can specify inputs and outputs.
As part of the _myRunCommands
target, use the Touch
task to create a file or update the timestamp if the file exists. You can name the file whatever you like, e.g. lastrun.txt
. This file is your "output". Your .sln file is your "input". If the .sln file has changed and has a newer timestamp then lastrun.txt
, the target will be run to update the lastrun.txt
file. Otherwise the target won't be run.