Monday, January 18, 2010

How to build a SharePoint WSP package as part of your Continuous Integration process

Having a continuous, repeatable, and automated build process is necessary when developing software - and developing custom solutions for SharePoint is no exception. In this article I will describe how to automate the creation of SharePoint WSP Solution files as part of your continuous integration build process. The article is laid out in the following sections:
  • SharePoint Features and Solutions
  • WSP Builder
  • Automating the Creation of your WSP Solution
If you are familiar and comfortable with SharePoint features and solutions, feel free to skip forward past the first two sections.

SharePoint Features and Solutions
The way that you develop for SharePoint is via Features. SharePoint Features are a collection of resources and XML configuration information which describes to SharePoint how a certain feature is structured. To provide a concrete example, take a look at the following link to see what goes into creating a Feature:

Anatomy of a SharePoint WSS v3 Feature Project in Visual Studio 2005

That's a fair bit of stuff! At a minimum you are typically looking at:
  • A Feature.xml file which defines the Feature and specifies the location of assemblies, files, dependencies, or properties that support the Feature.
  • A signed assembly to be installed in the GAC.
  • An Elements.xml configuration file which defines the elements that the Feature depends upon
In that article there is also a lot of fluff that is required to create a SharePoint Solution - which is what you need to create to actually deploy and install your Feature into SharePoint. The items that are created in that article which exist solely to create the SharePoint Solution are:
  • A Manifest.xml file to describe how to package the Solution
  • A DDF file which defines the structure and contents of the solution package
  • A custom MSBuild task which runs makecab to process the DDF file and create the .wsp Solution file.
WSPBuilder
WSPBuilder is an open source piece of software which really helps to simplify the task of creating SharePoint Features and Solutions. WSPBuilder consists of an executable program and a Visual Studio plug-in which aid developers when developing SharePoint Features. Here's a link to a page with a tonne of links to useful articles which explain WSPBuilder:
WSPBuilder documentation
When using WSPBuilder you do not need to know about the second grouping of objects that were created in the article which I referenced earlier. Namely, you will not need to create a Manifest.xml, a DDF file, or the custom MSBuild task to call makecab.exe.

When using the WSPBuilder Visual Studio add-in, developers get "right-click" > "add feature" functionality which really does help to bootstrap the development of Features. Not only that, WSPBuilder also helps by simplifying the following common tasks:
  • Deploying to the GAC
  • Creating Features
  • Generating SharePoint Solutions
  • Debugging
Each of these features can be accessed from within Visual Studio to help speed up the development process when developing SharePoint Features. The interesting part of this is that these services are actually provided by the underlying WSPBuilder.exe application. And this means that we can use this executable during our build to automatically generate SharePoint .wsp solution files as part of our continuous integration process.

Automating the Creation of your WSP Solution
Having used WSPBuilder, your Visual Studio will have a specific structure that conforms to how SharePoint is laid out in the 12 Root, GAC, and 80 Folder. And using the VS add-ins, your developers will have been able to easily create and deploy WSPs on their local development environments. Here is a view of the layout that I would use for a typical SharePoint development project:

ProjectStructure

When developing I can simply right click the My.SharePoint.FrontEnd project to get WSPBuilder options for deploying, debugging, or re-deploying assemblies to the GAC. However, in order to maintain order and control over the content of WSP files and have them versioned properly, it is best to generate the WSP files that will get pushed through into production automatically as part of your build process.

Creating a WSP package from your build process simply means that you will invoke WSPBuilder.exe as part of your CI build. Therefore the first thing that you must do is to ensure that you have access to WSPBuilder on your build server.

Once you have WSPBuilder on the build server it is a matter of adding some control flow to your build tasks so that it gets called after the Visual Studio project has been built. The control flow for your continuous build process should look similar to this:Creating a WSP package from your build process simply means that you will invoke WSPBuilder.exe as part of your CI build. Therefore the first thing that you must do is to ensure that you have access to WSPBuilder on your build server. Once you have WSPBuilder on the build server it is a matter of adding some control flow to your build tasks so that it gets called after the Visual Studio project has been built. The control flow for your continuous build process should look similar to this:

SharePointBuildProcess

In my case I am using MS Build to control the flow of the build process, but you could just as easily use NAnt or whatever build scripts you typically use to build your solutions.

Running through the MS Build script logic we see that, at the head of the MSBuild file, I would usually add some properties to provide runtime pointers to where MS Build can find various locations.Running through the MS Build script logic we see that, at the head of the MSBuild file, I would usually add some properties to provide runtime pointers to where MS Build can find various locations.

<PropertyGroup>
<Root>$(MSBuildStartupDirectory)</Root>
<WSPBuilderPath>c:\Program Files (x86)\WSPTools\WSPBuilderExtensions</WSPBuilderPath>
<WSPSolutionPath>$(Root)\$(build_branch_name)\MySharePointProject\My.SharePoint.FrontEnd</WSPSolutionPath>
</PropertyGroup> 

In the above snippet I have a property which points to the path of the WSPBuilder executable and another one (WSPSolutionPath) that points to the root path of the the Visual Studio project which has my features in it (typically I have 2 projects in my solution: 1 which has the code assembly and one which only has the feature definitions).

Notice that the WSPSolutionPath is composed by a variable which is passed into my build - $(build_branch_name) - from my continuous integration process. You can hard code this part of the path if you do not need the branch path to be dynamic.

Next up the I use an MS Build task to compile the solution. This builds the assembly which contains the code for WebParts, Workflows, FeatureReceivers, etc and which will ultimately reside in the GACNotice that the WSPSolutionPath is composed by a variable which is passed into my build - $(build_branch_name) - from my continuous integration process. You can hard code this part of the path if you do not need the branch path to be dynamic. Next up the I use an MSBuild task to compile the solution. This builds the assembly which contains the code for WebParts, Workflows, FeatureReceivers, etc and which will ultimately reside in the GAC.

<ItemGroup>
<ProjectToBuild Include="$(Root)\$(build_branch_name)\MySharePointProject\My.SharePoint.sln" />
</ItemGroup>

<MSBuild
Projects="@(ProjectToBuild)"
Targets="Build">

<Output
TaskParameter="TargetOutputs"
ItemName="AssembliesBuiltByChildProjects"
/>
</MSBuild> 

Once the solution has been built, I am able to run WSPBuilder to create a WSP package from the compiled artifacts.

<Exec Command='"$(WSPBuilderPath)\WSPBuilder.exe"
-SolutionPath "$(WSPSolutionPath)"
-12Path "$(WSPSolutionPath)\12"
-GACPath "$(WSPSolutionPath)\GAC"'
ContinueOnError='false' 
/> 


Notice that the GACPath argument expects any assmblies to be in a GAC folder of the feature project, I used a post-build script in my Core assembly project to copy the assembly across to this folder in my feature project:

xcopy "$(OutputDir)*.dll" "$(SolutionDir)My.SharePoint.FrontEnd\GAC\" /Y /R 

The final thing to do is to publish the WSP package to a release server so that it can be deployed into acceptance and production environments…

<MakeDir Directories="$(deploy_path)\$(build_number)" Condition="!Exists('$(deploy_path)\$(build_number)')" />

<ItemGroup>
<WSPSourceFiles Include="$(MSBuildProjectDirectory)\My.SharePoint.FrontEnd.wsp; $(WSPSolutionPath)\Deploy\*" />
</ItemGroup>

<Copy
SourceFiles="@(WSPSourceFiles)"
DestinationFolder="$(deploy_path)\$(build_number)"
/> 

As you can see, this is simply a matter of creating a folder and copying the resultant WSP file across.  Importantly you will note that when I create the release folder that I include the build number as part of the path.  This practice makes it very easy to keep your versioning aligned between source code, release notes, and deployable artifacts.

Updates
Jeremy Thake has uploaded a great screencast which shows how to do this (and more) using TFS which you can view here.

5 comments:

  1. Great post Darren! I'm literally prepping for my ALM track, always good to see how it's being approached. I want to try and get one default build file for WSPBuilder, VSeWSS and STSDev. To make it easy for people to get this going ;-)

    ReplyDelete
  2. Thanks for the post. Have you tried to do this with SharePoint 2010 and VisualStudio 2010 with build-in Deploy option ?

    ReplyDelete
  3. Yes, you can do it, and it works fine. But when building software to deploy into production in an enterprise, it is generally preferable to have these packages built as part of a formal build process.

    ReplyDelete
  4. Hi Darren Neimke

    Excellent. I have been searching for a good article like this for a long time. Very nice to view this post.

    ReplyDelete
  5. Hi Darren Neimke

    I'm a newbie to SharePoint development.I have few doubts regarding setting up a development environment for SharePoint development. I'm looking for a scenario where we will include the CI , version control, IT, ST etc. Do you have any useful articles from your side.

    ReplyDelete