If you want to leverage the many awesome C# 9 features, including roslyn source generators like ThisAssembly, all of which require the latest and greatest .NET 5.0 preview, it would be a pity to have to give up the safety net of your CI builds (whether GitHub Workflows or Azure DevOps pipelines) just because they don’t provide hosted images with the relevant bits.
This post shows how to install and use the latest Visual Studio preview from your build script.
Yes, it might just be enough to install the .NET Core RC and use
dotnet test. In some cases you do need a full Visual Studio depending on your project.
The key to enabling this scenario is a little awesome (if I might say so) dotnet global tool called dotnet-vs: “A global tool for running, managing and querying Visual Studio installations”. It’s a cool little thing Adrian Alonso and myself created to more easily manage multiple versions of Visual Studio installed side by side. It can get quite crazy at times.
The tool allows, among other things, to query installed VS versions and install new ones, including adding/removing components. It internally uses vswhere as well as the Visual Studio installer command line to achieve a seamless experience.
So, on to the actual scripts that are really quite simple.
name: build on: push jobs: build: runs-on: windows-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-dotnet@v1 with: dotnet-version: 3.1.x - run: dotnet tool update -g dotnet-vs - run: echo "::set-env name=MSB::$(vs where preview --prop=InstallationPath)" - run: vs install preview --quiet +Microsoft.VisualStudio.Component.ManagedDesktop.Core +Microsoft.NetCore.Component.DevelopmentTools if: env.MSB == '' - run: echo "::add-path::$(vs where preview --prop=InstallationPath)\MSBuild\Current\Bin" - run: msbuild -r - run: msbuild -t:test
Install/update to latest & greatest dotnet-vs by simply using
dotnet tool update -g. That will install the tool if it’s not there, and ensure it’s the latest otherwise. I do this because if VS preview requires some newer command args in the future, the latest
dotnet-vstool will likely support that too.
The syntax for setting an environment from a GH action is a bit weird, but the notable thing here is that the
runcommand will actually run Powershell Core by default, unlike on DevOps where it runs cmd.exe (on Windows agents, in both cases):
So we take advantage of that fact and just run the
vs wherecommand inline to set the value of the installation directory for a preview version of VS. The
dotnet-vstool where command will return the raw value from that execution, or an empty string if no such version is found.
We use that as the condition for the
vs installso that we only do so if the preview isn’t there already. Note how you can add any supported workload or component ID to the installation with the simple
+[ID]syntax. There are also shorter aliases for common workloads like
+core +desktop +azure +mobile, say. The ones I’m installing in this case are just the minium I need, so I can get the install in just about ~5 minutes!
We finally use the same “trick” as step 2 for adding the MSBuild path to the
%PATH%so that we can finally just run
All in all, pretty straightforward and concise. I love it how GitHub
run actions are rendered by default using the frst line of the command. I wish Azure DevOps did the same, instead of showing just
CmdLine and forcing you to always annotate steps with
pool: vmImage: 'windows-2019' steps: - checkout: self - task: UseDotNet@2 inputs: packageType: sdk version: 3.1.x performMultiLevelLookup: true - script: dotnet tool update -g dotnet-vs - pwsh: echo "##vso[task.setvariable variable=MSB]$(vs where preview --prop=InstallationPath)" - script: vs install preview --quiet +Microsoft.VisualStudio.Component.ManagedDesktop.Core +Microsoft.NetCore.Component.DevelopmentTools condition: eq(variables['MSB'], '') - pwsh: echo "##vso[task.prependpath]$(vs where preview --prop=InstallationPath)\MSBuild\Current\Bin" - script: msbuild -r - script: msbuild -t:test
(I removed all the
displayName for conciseness).
You can see that the structure is pretty much the same as for GitHub workflows. Note that we need to explicitly choose to run with powershell by using
pwsh instead of
script, so that the inline execution of
vs commands when expanding the string for the variables works the same way. We use the
##vso[task.XXX] syntax in this case instead.
The condition syntax in GitHub workflows is also so much nicer :).
And that is all you need to install quickly (both in ~5’ in this combination of components) and build in CI using the latest and greatest C# features!