Sometimes we need to include extra steps in the build process on a single machine involved in a project. Often this is based not on an environment specification itself, but rather on developers' personal preferences on how to approach their work. Small teams working on small projects have the highest probability of facing such problems since enforcing strict development standards for them might be an overkill.
The $(ComputerName)
environmental variable in a csproj
file comes to the rescue here:
<Target Name="PreBuild" AfterTargets="PreBuildEvent" Condition="Exists('$(ComputerName).prebuild.bat')"> <Exec Command="$(ComputerName).prebuild.bat" /> </Target>
Include this target in your project's csproj
file to run any script from YOUR-PC-NAME.prebuild.bat
file in the root folder of the project.
Notice a Condition
on the target: a script is to be called only in case a file with your machine's name exists in the root folder. That means that any team member can opt-out of this step without any additional settings on their side.
You can also put *.prebuild.bat
line in your .gitignore
file, because nobody likes your personal stuff in the source code you share with a team.
Something that you may face here is a blocked MSBuild if you run a task that takes significant time to finish while not being required for the rest of the build process or a task that does not exit at all without user interaction (e.x., your ng serve
or webpack --watch
process).
This StackOverflow answer suggests a very useful ExecAsync
implementation:
<!--Launch a Process in Parallel--> <UsingTask TaskName="ExecAsync" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> <ParameterGroup> <!--The file path is the full path to the executable file to run--> <FilePath ParameterType="System.String" Required="true" /> <!--The arguments should contain all the command line arguments that need to be sent to the application--> <Arguments ParameterType="System.String" Required="true" /> </ParameterGroup> <Task> <Code Type="Fragment" Language="cs"> <![CDATA[ System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo(FilePath, Arguments); processStartInfo.UseShellExecute = false; System.Diagnostics.Process.Start(processStartInfo); ]]> </Code> </Task> </UsingTask>
Now you can run your script with the following target:
<Target Name="PreBuild" AfterTargets="PreBuildEvent" Condition="Exists('$(ComputerName).prebuild.bat')"> <ExecAsync FilePath="cmd.exe" Arguments="/c $(ComputerName).prebuild.bat" /> </Target>
which will give you the same result without blocking the rest of the build process.
Bonus: what's going on in TARAS-LAPTOP.prebuild.bat
tasklist /nh /fi "imagename eq code.exe" | find /i "code.exe" > nul || code client
When I start my Debug build, an instance of VS Code is launched in the ./client
folder if there are none running already. Meanwhile, VS Code is configured to build Typescript files and watch for changes in them via yukidoi.blade-runner
extension.
Bonus 2: just executing a Target
that does not involve any scripts on a specific machine can be done with a file used as a flag:
<Target Name="CustomAction" AfterTargets="AnotherAction" Condition="Exists('$(ComputerName).msbuild.flag')">
... </Target>
Now this Target
is executed only if a file with a name YOUR-PC-NAME.msbuild.flag
is present.