Automatically Sync nupkg and project.json Dependencies
Recently while working on an open source .NET project,
I forgot to update the .nuspec
after changing a package
dependency in my project.json
. Of course the resulting nupkg
contained the wrong dependency. Fortunately, the package
wasn't published in that state, but I didn't want to risk such a thing
happening again.
I want the project to be buildable in Visual Studio immediately
after cloning, but there's no such constraint on producing the NuGet
package, so this means the project.json
has to be the source
of truth.
I opted to have the project's
simple-targets-csx
build script scrape the project.json
for the version of the
dependent package and supply the matching version as part of the
nuget pack
properties
option.
My initial implementation used a regular expression to extract the version, but my colleague Thomas Levesque suggested parsing the JSON to find the proper value.
I liked the idea, but pulling in something like Json.NET seemd heavy. A little Googling later, I found Brandur Leach's Using the Little-known Built-in .NET JSON Parser that described the built-in JsonReaderWriterFactory. This seemed like just the ticket. A few minutes later, I was up and running with these sections of the build script
targets.Add(
"pack",
DependsOn("build", "outputDirectory"),
() =>
{
var fakeItEasyVersion = GetDependencyVersion("FakeItEasy");
Cmd(nuget, $"pack {nuspec} -Version {version} -Properties FakeItEasyVersion={fakeItEasyVersion} -OutputDirectory {outputDirectory} -NoPackageAnalysis");
});
…
public string GetDependencyVersion(string packageName)
{
byte[] buffer = File.ReadAllBytes(projectJsonPath);
XmlReader reader = JsonReaderWriterFactory.CreateJsonReader(buffer, new XmlDictionaryReaderQuotas());
XElement root = XElement.Load(reader);
return root.Element("dependencies").Element(packageName).Value;
}
which find the "3.0.0-rc001-build000097" from the project.json:
{
"dependencies": {
"FakeItEasy": "3.0.0-rc001-build000097",
"StyleCop.Analyzers": "1.1.0-beta001"
},
…
and combine it with this portion of the .nuspec
:
<dependencies>
<dependency id="FakeItEasy" version="[$FakeItEasyVersion$,4)" />
</dependencies>
Of course, a property could be added for each dependency. Do this, and you can rest easy, knowing you'll never get a dependency mismatch again.