Slides & code of MSDN Live Meeting: CI using TFS11 & NuGet

Posted by Xavier Decoster on Tuesday, May 08, 2012 at 16:09

Thanks everyone for joining this session!

As promised, here are the slides and code used during the presentation. The Channel9 screencast is now also available.

MSDN Live Meeting - CI using TFS11 & NuGet - demo code.zip (2.40 mb)

Tags: , , , ,

ALM | Community | MyGet | NuGet | TFS

Install-NuSpec & Enable-PackagePush: create, build & push NuGet packages anywhere

Posted by Xavier Decoster on Sunday, May 06, 2012 at 15:27

This short post is basically combining some of my recent posts (this one and that one) into one. Actually, into one single NuGet package :) 

Basically, this one single package will allow me to automate and speed up package creation and publication, and it will run anywhere you can run the NuGet command line, because I only use nuget.exe and MSBuild to perform these actions. To set it up, I use a NuGet package (Install-Package NuSpec) and some PowerShell, but that's only to put the pieces of the puzzle in the right place, and give you some commands in Visual Studio. Once you're done, simply uninstall the package.

So, in short:

  1. Enable Package Restore to get the .nuget folder (which contains nuget.exe and some nuget.targets file I'll extend)
  2. Install-Package NuSpec (once per solution, target project doesn't matter)
  3. Install-NuSpec <projectName> [-EnablePackageBuild] (for every project you want to trigger a package build)
  4. Enable-PackagePush <projectName> (for every project you want to enable auto-push)
  5. Uninstall-Package NuSpec (once you're finished with steps 1-4 for the solution)
A more detailed Readme is available on Github (where the sources are if you fancy some PowerShell).
The package can be found on NuGet.

If you're using MyGet already, you simply need to set the feedname and your own personal API-key in the NuGet.Extensions.targets file you'll find under the $(SolutionDir)\.nuget folder. If you're not using MyGet, simply replace the entire PushPkgSource and SymbolsPkgSource URLs by the one of your choosing.

Tags: ,

NuGet | OpenSource

Install-Package NuSpec

Posted by Xavier Decoster on Friday, April 27, 2012 at 13:45

If you are like me and regularly produce NuGet packages, then you often deal with NuSpec files. I always found it annoying that I had to leave my Visual Studio environment in order to create a .nuspec file. Well, I've finally automated this step and published it on Github and on the NuGet Gallery. Feel free to fork it, contribute and provide feedback!

What this package does

Plain simple:

  • It extends the NuGet Package Manager Console with a new PowerShell cmdlet, called Install-NuSpec
  • It adds the nuspec XSD's to the Solution Items solution-folder, providing you with IntelliSense when editing the nuspec file.
  • It adds a tokenized nuspec file to the target project and renames the nuspec file to <projectname>.nuspec (which allows the PackageBuild feature - or nuget pack <project> - to pick it up as well)
Please note that this package obsoletes my old NuGet.Manifest.Xsd package as well.

Under the hood, I'm using an XML template for the generated .nuspec files, which looks like this:
<?xml version="1.0"?>
<!-- 
This tokenized .nuspec manifest file is targeting the latest NuGet namespace,
which ensures you can benefit from the latest packaging features.

If desired, you can change the XML-namespace and target the original XSD.
To do so, replace the current package declaration by the following:

<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">

Run "nuget.exe pack <project>" to build a nuget package for this project
using this tokenized nuspec file.

-->
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <version>$version$</version>
    <authors>$author$</authors>
    <owners />
    <id>$id$</id>
    <title />
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
  </metadata>
  <files />
</package>

Install the package use Install-Package NuSpec.


And start using the Install-NuSpec command instead of losing time messing arround with files and windows and stuff. (kittens die when you do that)

Tags: ,

NuGet | OpenSource

NuGet $version$ token explained

Posted by Xavier Decoster on Thursday, April 26, 2012 at 14:25

Many questions that often come to mind when building NuGet packages are related to versioning. There's one question in particular I'd like to post here because it's one of the easier to answer. The question is: How do I use the $version$ token in the NuGet manifest (nuspec) file? Where does it get the version number from?

If you look at the NuGet docs explaining the nuspec replacement tokens, it states that the following - if it doesn't, my pull request got accepted :) - The assembly version as specified by the assembly's AssemblyVersionAttribute.

That is not entirely accurate (got a pull request pending on the docs). Consider the following AssemblyInfo.cs file contents for example.

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.2.0")]

This is where most people get confused. I won’t get into the details of which version attribute you should or should not use, as there can be good reasons to use either one of them in different scenarios. I’ll focus on how nuget is using this information to provide a version number to the $version$ replacement token in the nuspec file.

Building a NuGet package using a tokenized nuspec file that relies on assembly information can be achieved in various ways, for instance:

  1. nuget spec <csproj> to generate the tokenized nuspec, followed by nuget pack <csproj>
  2. nuget spec –a <assemblyPath> inside the csproj folder to generate a non-tokenized nuspec (so with the metadata already filled in), followed by nuget pack <nuspec>

Basically, it comes down to this:

  • If the AssemblyInformationalVersion attribute is available, then that one is used.
  • If the AssemblyInformationalVersion attribute is not available, then the AssemblyVersion attribute is used.
  • If none of the above are specified, your assembly will have a version number of 0.0.0.0, as well as the resulting package.
  • NuGet totally ignores the AssemblyFileVersion attribute.

Note that this behavior is the same when skipping the nuspec at all and building a nuget package directly from an assembly, using using nuget pack <assembly.dll>.

Tags:

NuGet

Creating ReSharper Live Templates & distribute them using NuGet

Posted by Xavier Decoster on Wednesday, April 18, 2012 at 20:51

In one of my recent projects I created some ReSharper Live Templates in order for other developers to easily create some code using a predefined class template. Live templates can significantly speed up the implementation of such classes, because developers only need to provide some minimal information (such as the class name and maybe some generic type parameters and such). There’s also less room for accidental copy-pasting. Yeah, pressing CTRL+V after CTRL-C should be mapped to some macro that makes Visual Studio crash! :)

Example use case

But seriously, file templates can come in quite handy. Consider the following piece of code that needs to be converted into a ReSharper file template. It represents a custom Comparer implementation for a given contract that has a unique key. It's exported using a custom MEF export attribute that exposes some metadata. Such design is quite common for instance when some application dynamically loads assemblies containing such comparers and needs to find the best matching comparer for a given contract.

[Export(typeof(MyContractComparer))]
[ContractComparer(typeof(MyContract))]
public partial class MyContractComparer : KeyComparer<MyContract, long>
{

	protected override Expression<Func<MyContract, long>> KeyProperty
	{
		get { return contract => contract.Id; }
	}
}

Imagine that various of those classes need to be implemented, with potentially a different base type and more comparison logic, but in the end they're all minor differences in implementation.

Exploring ReSharper's Templates

Here's where templates come in handy. Creating such file template in ReSharper is pretty straightforward and reveals some cool options, such as type completion and smart snippet completion. ReSharper comes with a built-in Templates Explorer which you'll find in the menu under ReSharper > Templates Explorer.

In the dialog that opens, you'll notice 3 tabs. I want to create a C# file template so the File Templates tab is the one we need. You'll notice the 4 default C# file templates provided by ReSharper out-of-the-box when you click on C# on the left. These are the templates used when right clicking a project and selecting Add > New from Template > ...

Creating the File Template

That's where my new File Template needs to appear, so let's create a new one. I'll call it KeyComparer (click on the image for a high-res view). The description is what you'll see in the right-click context menu above. The default file name needs to include the extension. Notice that this is purely to indicate ReSharper that it should create (in this case) a C# file using the .cs extension. You won't see this in the dialog that will prompt you for the name of the KeyComparer when using the File Template.

You'll notice immediately that there are some placeholders marked in the code window on the left, which also appear in the variables list on the right. Here's where the real magic kicks in: you can assign macros to each of these placeholders and select which ones are editable or not (and even which occurance if the placeholder occurs multiple times in the same template). You see the placeholders in the red box? Those are the only ones that the developer will need to provide when using this template while creating this class. That's like: provide a name, use autocomplete + tab key three times, save the file and done! In this sample use case, you simply provide the type you want to implement the comparer for, you provide the type of the KeyProperty, and you select the property on the compared type that represents the unique key of the object.

There are quite a lot of macros available which allow you to do a lot of neat stuff (some macros can use other variables or contextual information of the file you create). Just play with it and discover for yourself. Don't forget to add the newly created template to the quicklist by dragging and dropping it.

Distribute the template in a NuGet package

It's very cool if you have a set of templates you find useful, but why would you keep them for yourself? This particular template for instance could be considered part of the product that contains the base type. Guess what: the assembly containing these base types and MEF attributes is being shipped as a NuGet package. So why not make the package smarter and embed these ReSharper templates and install them into the consuming target solution?

ReSharper support layers of settings, and one of them is on the solution level. This is the <SolutionName>.DotSettings file you often find in your code repository. This basically is an XML file, and NuGet supports XML transforms (well, it's called config transforms but it works on any XML file). Great, but sadly enough, I don't know the filename (or solution name) upfront so I cannot take benefit from that. I still had to figure out how to find the name of the target solution and a way to perform this transformation upon installation. If the target file doesn't exist yet, we need to copy and rename our source file. If it does exist, we need to somehow merge the two (for now, I'll only append). Luckily, there's PowerShell: any NuGet package can hook into its own installation using an install.ps1 file in the Tools folder of the package. And how convenient: we get access to some handy variables amongst which $dte (Visual Studio DTE)!

That's enough information I think, here's the script that will take the file Tools\Comparers.Templates.DotSettings and install it:

param($installPath, $toolsPath, $package, $project)

$resharperSettingsPath = [System.IO.Path]::Combine($toolsPath, 'Comparers.Templates.DotSettings')

$slnFullName = $dte.Solution.FullName
$teamsettingsFileName = $slnFullName + ".DotSettings"

if(-not([System.IO.File]::Exists($teamsettingsFileName))){
Copy-Item -Path $resharperSettingsPath -Destination $teamsettingsFileName -ErrorAction stop
}
else{
    $newContents = (Get-Content $resharperSettingsPath);
    $newContents = $newContents -Replace "<wpf:ResourceDictionary xml:space=""preserve"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:s=""clr-namespace:System;assembly=mscorlib"" xmlns:ss=""urn:shemas-jetbrains-com:settings-storage-xaml"" xmlns:wpf=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">", "";
    (Get-Content $teamsettingsFileName)| Foreach { $_ -Replace "</wpf:ResourceDictionary>", "$newContents" }| Set-Content $teamsettingsFileName;
}

Write-Host "Successfully installed Resharper Live Templates into '$teamsettingsFileName'"

Note: there's likely more to it to properly update and uninstall these templates as part of the NuGet package, and I'm not saying the merge/append process is ideal (proper XML processing would be better), but I'll tackle that problem when it occurs. For now, you can at least distribute your templates together with the NuGet package they belong to. If you have no issue with overwriting the entire file, then this solution will do.

Feel free to post your solution :)

Tags: , ,

ALM | NuGet | ReSharper

Author info

Xavier Decoster is an MCP ASP.NET/Silverlight and a Certified Scrum Master. He works as a Technical Consultant ALM for RealDolmen, one of Belgium's biggest ICT companies.
He's passionate about .NET software development in all its facets, including but not limited to tooling such as Visual Studio, Team Foundation Server, NuGet etc.

He is a co-founder of MyGet.org, which is a NuGet-as-a-Service platform on Windows Azure, where he builds further on top of his experience as a web developer (ASP.NET & Silverlight) and his broad ALM interests.
From the point of view that every software developer deserves to work in an environment that supports efficiency and productivity, he does a best effort to contribute to the Community, as a speaker (Agile.NET, VISUG, UgiALT.NET), as an author, as a blogger, and through various open source projects.

[more about me] [email me]

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

My Book

Apress Pro NuGet

I'm a MEET member

I'm a MEET member