Archive

Archive for June, 2012

Optimizing your SharePoint development environment – Versioning

June 25, 2012 1 comment

Today I’ve spent some time optimizing my Visual Studio settings in order to automatically update version numbers in my SharePoint projects. For this I’ve look at adding version numbers for assemblies and for solution packages.

In this post I’ll start by explaining the theory and I will end with how I’ve changed my Visual Studio settings.

The theory

Assembly versions

For assemblies, you have two different version numbers you could update.

  • Assembly Version: This is the version number used by the .NET framework during build and at runtime to locate, link and load the assemblies. When you add reference to any assembly in your project, it is this version number which gets embedded. At runtime, CLR looks for assembly with this version number to load.
  • Assembly File Version: This is the version number given to file as in file system. It is displayed by Windows Explorer. It’s never used by .NET framework or runtime for referencing.

Challenges with assemblies in WSP’s

Updating the assembly version number for your SharePoint solutions will provide you with some challenges. The main challenges are:

  • SharePoint stores assembly references including assembly version in many different places:
    • ASPX
    • C# Code
    • Web Part XML
    • Web Config
    • Control Templates
    • Creating a new version would require a lot of additional work, since it would mean you need to modify a large number of files to update the assembly version and would require tooling to upgrade artifacts in the content databases.

SharePoint Solution Packages (WSP)

Solutions don’t have a version number included unless you add one in the name. It is recommended to add a version number, because this is the only way to know which version of your solution is deployed (only the name is listed in the solution overview page or when you check the installed solutions via PowerShell).

Important:The name is only used for displaying which solutions are installed, internally SharePoint uses the identifier of the solution (a GUID).

To be consistent with the naming conventions on features, add the namespace to the solution name too. For instance Peter.SP2010.Intranet.Core_v1.0.12177.wsp for a solution adding core functionality.

I use the following naming convention for solutions:

<Company>.SP2010.<ApplicationName>.<ApplicationBuildingBlock>_<version>.wsp

For example:

Peter.SP2010.Intranet.SiteDefinitions_v1.0.12177.wsp

Version numbers

Version numbers are written as:

<major>.<minor>.<build>.<revision>

I incremented the version numbers as followed:

  • Major: A significant change to the UI or code base is reflected in the major number. This mainly happens when a complete new version of the solution has been created
  • Minor: Providing a new release package with huge changes. This is something I tend to avoid, since I don’t want to update all versions numbers in non-code files.
  • Build: Indicating which day of which year the build is made. The format for the build number is YYDDD. The YY is indicating the last two digits of the year and DDD is indicating the day of the year (1-365).
  • Revision: Is used to indicate if the release is contains a bugfix. If the number is higher than 0 then that indicates that the release contains a bugfix from the same day.

The implementation

To update the AssemblyFileVersion and the solution naming, I’ve updated the project file manually and added a pre and post build event.

Ensure a package is created during the build event

Most times I perform a build, I also want the WSP file to be generated. To allow this, you can add the following XML to your project file:

<PostBuildEventDependsOn>

$(PostBuildEventDependsOn);

CreatePackage;

</PostBuildEventDependsOn>

This ensures that on every build action, a WSP is created as well. I need this file to update the name to include the version number in the next steps.


Update the AssemblyFileVersion

Notes

The following PowerShell script can be used to update the AssemblyFileVersion when building your project. Important items to note:

  • The build events are triggered from the folder in which the assembly is build. So this will be either from [projectfolder]\bin\debug or [projectfolder]\bin\release.
  • When using TFS, you should make sure the path to the Visual Studio folder containing tf.exe is added to the PATH environment variable and the line to check the file out should be enabled.
  • I only update the AssemblyFileVersion when generating a release package. For debug on my development machine I don’t think it’s needed.

Usage

To use this script, please it somewhere on your development machine and then start it in a pre-build event (properties of your project > Build Events). In my case I start it as stated below. I use a relative path since it’s part of my TFS source and I don’t know the mapping of other developers:

if $(ConfigurationName) == Release powershell.exe ..\..\..\..\..\BuildScripts\UpdateFileVersionAssembly.ps1

The script

#-------------------------------------------------------------------------------            
# Displays how to use this script.            
#-------------------------------------------------------------------------------            
function Help {            
    "Sets the AssemblyFileVersion of AssemblyInfo.cs files`n"            
    ".\SetVersion.ps1 [VersionNumber]`n"            
    " [VersionNumber] The version number to set, for example: 1.1.9301.0"            
    " If not provided, a version number will be generated.`n"            
}            

#-------------------------------------------------------------------------------            
# Generate a version number.            
# Note: customize this function to generate it using your version schema.            
#-------------------------------------------------------------------------------            
function Generate-VersionNumber {            
    $today = Get-Date            
    return "1.0." + ( ($today.year - 2000) * 1000 + $today.DayOfYear )+ ".0"            
}            

#-------------------------------------------------------------------------------            
# Update version numbers of AssemblyInfo.cs            
#-------------------------------------------------------------------------------            
function Update-AssemblyInfoFiles ([string] $version) {            

    $fileVersionPattern = 'AssemblyFileVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)'            
    $fileVersion = 'AssemblyFileVersion("' + $version + '")';            

    $scriptPath = pwd            
    $scriptPath = Split-Path -Path (Split-Path -Path $scriptPath -Parent) -Parent            

    $scriptPath | Get-ChildItem -r -filter AssemblyInfo.cs | ForEach-Object {            
        $filename = $_.Directory.ToString() + '\' + $_.Name            
        $filename + ' -> ' + $version            

        # If you are using a source control that requires to check-out files before             
        # modifying them, make sure to check-out the file here.            

  # Ensure the TFS command line tool is accessible            
  #$env:Path =$env:Path + ";D:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\"            

  # For example, TFS will require the following command:            
        # tf checkout $filename            

        (Get-Content $filename) | ForEach-Object {            
            % {$_ -replace $fileVersionPattern, $fileVersion }            
        } | Set-Content $filename            
    }            
}            

#-------------------------------------------------------------------------------            
# Parse arguments.            
#-------------------------------------------------------------------------------            
if ($args -ne $null) {            
    $version = $args[0]            
    if (($version -eq '/?') -or ($version -notmatch "[0-9]+(\.([0-9]+|\*)){1,3}")) {            
        Help            
        return;            
    }            
} else {            
    $version =  Generate-VersionNumber            
}            

Update-AssemblyInfoFiles $version

Update the Solution name

Notes

The following PowerShell script can be used to update the solution name when building your project. Important items to note:

  • You should have updated the project file to generate a solution package on build.
  • The build events are triggered from the folder in which the assembly is build. So this will be either from [projectfolder]\bin\debug or [projectfolder]\bin\release.
  • The script makes a copy of the solution to a different location in my mapped source tree. Make sure the $copyPath is valid for you. If you just want to rename it, use Move-Item instead of Copy-Item.

Usage

To use this script, please it somewhere on your development machine and then start it in a post-build event (properties of your project > Build Events). In my case I start it as stated below. I use a relative path since it’s part of my TFS source and I don’t know the mapping of other developers:

if $(ConfigurationName) == Release powershell.exe ..\..\..\..\..\BuildScripts\UpdateWSPName.ps1

The script

#-------------------------------------------------------------------------------            
# Displays how to use this script.            
#-------------------------------------------------------------------------------            
function Help {            
    "Sets the WSP name to include a version`n"            
    ".\SetVersion.ps1 [VersionNumber]`n"            
    "   [VersionNumber]     The version number to set, for example: 1.1.9301.0"            
    "                       If not provided, a version number will be generated.`n"            
}            
            
#-------------------------------------------------------------------------------            
# Generate a version number.            
# Note: customize this function to generate it using your version schema.            
#-------------------------------------------------------------------------------            
function Generate-VersionNumber {            
    $today = Get-Date            
    return "1.0." + ( ($today.year - 2000) * 1000 + $today.DayOfYear )+ ".0"            
}            
             
#-------------------------------------------------------------------------------            
# Update version numbers of WSP file            
#-------------------------------------------------------------------------------            
function Update-WSPFile ([string] $version) {               
    # Determine the paths            
    $generatedPath = pwd            
    $copyPath = pwd            
    #$copyPath = Join-Path -Path (Split-Path -Path (Split-Path -Path (Split-Path -Path $copyPath -Parent) -Parent) -Parent)  -ChildPath "\_deployment\WSP\"            
            
    $generatedPath | Get-ChildItem -filter "*.wsp"| ForEach-Object {            
        # Remove previous version from WSPFolder            
        $copyPath | Get-ChildItem -filter ($_.Name.TrimEnd(".wsp") + "*.wsp") | ForEach-Object {            
            remove-item $_.fullname            
        }            
                    
        # Copy to deployment folder            
        $filenameOld = $_.Directory.ToString() + "\"+ $_.Name            
        $filenameNew = $copyPath.ToString() + "\" + $_.Name.TrimEnd(".wsp") + "_v" + $version + ".wsp"            
        Copy-Item $filenameOld $filenameNew            
    }            
}            
            
#-------------------------------------------------------------------------------            
# Parse arguments.            
#-------------------------------------------------------------------------------            
if ($args -ne $null) {            
    $version = $args[0]            
    if (($version -eq '/?') -or ($version -notmatch "[0-9]+(\.([0-9]+|\*)){1,3}")) {            
        Help            
        return;            
    }            
} else {            
    $version =  Generate-VersionNumber            
}            
            
Update-WSPFile $version

Credits

I made some small changes to the script which you can find here: http://www.luisrocha.net/2009/11/setting-assembly-version-with-windows.html

Advertisements
Ben Prins

What I want to remember about SharePoint

blog.frederique.harmsze.nl

my world of work and user experiences

Bram de Jager - Coder, Speaker, Author

Office 365, SharePoint and Azure