Home > Uncategorized > SharePoint deployment packaging

SharePoint deployment packaging

November 27th, 2010 Leave a comment Go to comments

In this blog post I discuss a strategy for adding migrations and scripting to the deployment of SharePoint solutions. What was implicit in their was that we were packing the SharePoint solutions (wsp file) into a release package that had scripting. I documented here the types of scripts we used in order to get automated deployments.

Taking a step back, the reasons we went down this approach was that in practice:

  1. in the first sprint, we lost 2.5 days times 3 developers worth of work alone in SharePoint API (funky-ness: eg poor error reporting, API bugs)
  2. developers are often waiting long periods of time for deployments
  3. when we did do “quick” deploys they were unreliable (ie pushing into the 14 hive), say with a javascript deployment (eg CKS.Dev.Server.vsix)

To do this, we had a take step back from delivering functions and delivering stability. This actually took us about a month to get under control – I wish I could send a particular corporation the bill for an under-finished product.

Therefore, beware. If you are reading this and this is new to you, you are likely to need to build in an initial theme over the first month or so: Stability of code base and its deployment. This is of course not a problem exclusive to SharePoint.

Approach:

  • map out the value stream for deployment through environment, identify pain points (result: scripting but not automation)
  • start scripted deployments
  • solve instability issues

Solutions:

  • versioned release packages – see below for the packing.proj msbuild tasks
  • scripted deployments
  • migrations as part of deployment
  • general rule of no

Results

  1. a standard deployment now takes between 1-3 mins (each scripted installation reports time taken)
  2. the biggest lag is still the bootstrapping process that SharePoint undergoes with a new deployment

package.proj

This packaging project is an adaption on the sample deployment project found here. In that sample, you’ll see the need for dependencies in the lib/ folder (such as 7zip for compression). Down in the script you might also notice that we include migratordotnet for managing releases which actually requires original binaries – I need to get back to this issue and try not to included binaries like this.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="HelpBuild"  ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
	    <Major>0</Major>
	    <Minor>1</Minor>
	    <Build>0</Build>
	  </PropertyGroup>

  <PropertyGroup>
    <Revision Condition="'$(Revision)'==''">0</Revision>
    <Version Condition="'$(Version)'==''">$(Major).$(Minor).$(Build).$(Revision)</Version>
    <DropLocation Condition="'$(DropLocation)'==''">$(MSBuildProjectDirectory)\CodeToDeploy\Publish</DropLocation>
    <BuildCmd Condition="'$(BuildCmd)'==''">ReBuild</BuildCmd>
    <ReleaseEnvironment Condition="'$(ReleaseEnvironment)'==''">Test</ReleaseEnvironment>


    <ReleaseName>MySites-$(ReleaseEnvironment)</ReleaseName>
    <ReleasePath>$(DropLocation)\..\Releases</ReleasePath>
    <DropLocationWsp>$(DropLocation)\wsp</DropLocationWsp>
    <BinariesRoot>$(MSBuildProjectDirectory)\src\Site</BinariesRoot>
    <LibRoot>$(MSBuildProjectDirectory)\lib</LibRoot>
    <WspRoot Condition="'$(WspOutDir)'==''">$(BinariesRoot)</WspRoot>
    <ReleaseZipFile>$(ReleasePath)\Site-$(Version).zip</ReleaseZipFile>

    <ExtractPath>$(DropLocation)\..\Deploy</ExtractPath>

    <Zip>$(MSBuildProjectDirectory)\lib\7z\7z.exe</Zip> 
  </PropertyGroup>

  <ProjectExtensions>
    <Description>Build Releasable MySites</Description>
  </ProjectExtensions>

  <ItemGroup>
    <SolutionToBuild Include="src\Site.sln">
      <Properties>Configuration=Release;Platform=x64;OutDir=$(WspRoot)\bin\x64\Release\</Properties>
    </SolutionToBuild>
    <WspToBuild Include="$(WspRoot)\UI.csproj">
      <Properties>Configuration=Release;Platform=x64;OutDir=$(WspRoot)\bin\x64\Release\</Properties>
    </WspToBuild>
    <WspFiles Include="$(BinariesRoot)\**\*\*.wsp" />
  </ItemGroup>

  <ItemGroup>
	  
    <TasksFiles Include="scripts\deploy.ps1" />
    <TasksFiles Include="scripts\deploy\migrations.ps1;
                         scripts\deploy\deploy.ps1;
                         scripts\psake.psm1;
                         scripts\deploy\install.ps1" />
    
    <MigrationFiles Include="$(WspRoot)\bin\x64\Release\Infrastructure.dll;
                             $(WspRoot)\bin\x64\Release\Domain.dll" /> 
    <MigratorFiles Include="$(LibRoot)\migratordotnet\*" /> 
  </ItemGroup>

  <Target Name="Package" DependsOnTargets="Clean;Version-Writeable;Version;Compile;Version-Reset;Version-ReadOnly;Publish;Zip"/>
  <Target Name="Install" DependsOnTargets="Package;Extract;Deploy"/>

  <Target Name="Compile">
    <MSBuild Projects="@(SolutionToBuild)" Targets="Rebuild" />
    <CallTarget Targets="PackageWsp" />
  </Target>

  <Target Name="PackageWsp">
    <MSBuild Projects="@(WspToBuild)" Targets="ReBuild;Package" />
  </Target>

  <Target Name="Publish">
    <MakeDir Directories="$(DropLocationWsp)" Condition = "!Exists('$(DropLocationWsp)')" />
    
    <Copy SourceFiles="@(WspFiles)" DestinationFolder ="$(DropLocationWsp)" SkipUnchangedFiles="true"/>
    <Copy SourceFiles="@(TasksFiles)" DestinationFolder ="$(DropLocation)\scripts\%(TasksFiles.RecursiveDir)" SkipUnchangedFiles="true" />
    
    <Copy SourceFiles="@(MigrationFiles)" DestinationFolder ="$(DropLocation)\lib\%(MigrationFiles.RecursiveDir)" SkipUnchangedFiles="true" />
    <Copy SourceFiles="@(MigratorFiles)" DestinationFolder ="$(DropLocation)\lib\migratordotnet\%(MigratorFiles.RecursiveDir)" SkipUnchangedFiles="true" />
    
    <Exec Command="echo .> &quot;$(DropLocation)\$(Version)&quot;"/>
    
    <Exec Command="echo powershell -ExecutionPolicy Unrestricted -Command &quot; &amp;{import-module .\scripts\psake.psm1; Invoke-Psake Install}&quot; > &quot;$(DropLocation)\Install.bat&quot;"/>
    <Exec Command="echo powershell -ExecutionPolicy Unrestricted -NoExit -Command &quot; &amp;{import-module .\scripts\psake.psm1; Invoke-Psake -docs}&quot; > &quot;$(DropLocation)\here.cmd&quot;"/>  
    <Exec Command="echo Include .\scripts\migrations.ps1; Include .\scripts\deploy.ps1; Include .\scripts\install.ps1 > &quot;$(DropLocation)\default.ps1&quot;"/>  
  </Target>

  <Target Name="Clean" DependsOnTargets="CleanPublish;CleanReleases" >
    <RemoveDir Directories="$(DropLocation)\.." />
  </Target>

  <Target Name="CleanPublish">
    <RemoveDir Directories="$(DropLocation)" />
  </Target>

  <Target Name="CleanReleases">
    <RemoveDir Directories="$(ReleasePath)" />
    <RemoveDir Directories="$(ExtractPath)" />
  </Target>

  <Target Name="Zip">
    <MakeDir Directories="$(ReleasePath)" Condition = "!Exists('$(ReleasePath)')" />
    <Exec Command="$(Zip) a -tzip %22$(ReleaseZipFile)%22" WorkingDirectory="$(DropLocation)"/>
  </Target>

  <Target Name="Extract">
    <MakeDir Directories="$(ExtractPath)"  Condition = "!Exists('$(ExtractPath)')"/>
    <Exec Command="$(Zip) x %22$(ReleaseZipFile)%22 -o$(ExtractPath)" WorkingDirectory="$(DropLocation)"/>
  </Target>

  <Target Name="Deploy">
    <Exec Command="$(ExtractPath)\deploy.bat $(ExtractPath)"  WorkingDirectory="$(ExtractPath)" ContinueOnError="false" />
  </Target>


  <Target Name="HelpBuild">
    <Message Text="

    msbuild /t:Package

    Examples:
      msbuild /t:Install
      msbuild /t:Install /p:ReleaseEnvironment=Test
      msbuild @build.properties /t:Package /v:d 

    Variables that can be overridden:
      DropLocation=C:\Binaries
      ReleaseEnvironment=Dev|[Test]|Prod
      BuildCmd=Build|[Rebuild] 

    Targets:
     - Compile
     - Clean
     - CleanReleases
     - Publish
     - Zip
     - Extract
     - Deploy
     - PackageWsp

     - Package (Compile;Clean;Publish;Zip)
     - Install (Compile;Clean;Publish;Zip;Extract;Deploy)

    Log output: msbuild.log
             " />
  </Target>

</Project>	
Categories: Uncategorized Tags: , ,