Creating a Nuget Package For Your Analyzer
Once you have developed a nice set of analyzers, you may want to share them with the world. Nuget is the most common way of sharing libraries these days and in Visual Studio 2015, you can add analyzers via Nuget packages. If you start with the Visual Studio templates to create your analyzers and you used the Analyzer With Code Fix (Nuget + VSIX)
template, then your project is already generating the Nuget package for you. Just look in your output directory and you should see a {ProjectName}.Nupkg
file.
To see how this is implemented, we can first look at the post build step for the analyzer project. You will see that it calls out to nuget.exe
to pack using a .nuspec
file.
"$(SolutionDir)\packages\NuGet.CommandLine.2.8.2\tools\NuGet.exe" pack Diagnostic.nuspec -NoPackageAnalysis -OutputDirectory .
Looking into the Diagnostic.nuspec
file in the project, we see the following.
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>AnalyzerSamples</id>
<version>1.0.0.0</version>
<title>AnalyzerSamples</title>
<authors>AnalyzerSamples</authors>
<owners>AnalyzerSamples</owners>
<licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
<projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
<iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>AnalyzerSamples</description>
<releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
<copyright>Copyright</copyright>
<tags>AnalyzerSamples, analyzers</tags>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System" targetFramework="" />
</frameworkAssemblies>
</metadata>
<files>
<file src="*.dll" target="tools\analyzers\" exclude="**\Microsoft.CodeAnalysis.*;**\System.Collections.Immutable.*;**\System.Reflection.Metadata.*" />
<file src="tools\*.ps1" target="tools\" />
</files>
</package>
The metadata section of the Diagnostic.nuspec
is pretty standard. If you are unsure what values to provide, the Nuspec Reference page can provide you guidance. The more interesting part of this .nuspec
is the files
section. The first file
entry copies the output DLLs to the tools\analyzers
output folder. This is a convention for analyzers as outlined in the Nuget Analayzers Conventions documentation. If you need to target specific languages or framework versions with your analyzer, you can use a more complex folder structure as described in the conventions document. For consumers using Nuget 3 with a project.json, these conventions are all that are needed to install your analyzers. However, for Nuget 2 users with a packages.config file, you will need the second file
entry as described below.
The second file
entry copies a few PowerShell scripts to your nuget package that will be run on the install and uninstall of your project. The project contains two scripts install.ps1
and uninstall.ps1
which are run when your analyzer package is installed and uninstalled respectively. For more information on PowerShell scripts in nuget packages, see the Creating and Publishing a Package documentation.
Now we can look into the install and uninstall scripts to see what they do. The install.ps1
script starts with the following
param($installPath, $toolsPath, $package, $project)
$analyzersPath = join-path $toolsPath "analyzers"
# Install the language agnostic analyzers.
foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll)
{
if($project.Object.AnalyzerReferences)
{
$project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)
}
}
This determines the analyzers path using the $toolsPath
variable passed into the function and then it loops over all of the DLLs in the $toolsPath\analzyers
folder and calls the AnalyzerReferences.Add
method to add the DLL as an analyzer reference. The next section of the install.ps1
does the following:
# Install language specific analyzers.
# $project.Type gives the language name like (C# or VB.NET)
$languageAnalyzersPath = join-path $analyzersPath $project.Type
foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll)
{
if($project.Object.AnalyzerReferences)
{
$project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)
}
}
This section of the script basically does the same thing as the first, except that it looks in the $toolsPath\analzyers\{language}
folder for all DLLs and then adds them as analyzers to the project.
The uninstall.ps1 just does the reverse of the install and calls the Remove
method on the AnalyzerReferences
object.
That's it. When you build, the nuget package is generated for you. If you want to push it up to the official nuget servers, you can follow the documentation in the Publishing in Nuget Gallery section of the Creating and Publishing A Package nuget documentation. As you can see, creating a Nuget package for your analyzer is very easy and if you are taking the time to create quality analyzers, then you should put forth the extra effort to make them as easy to install and use as possible.