Automate SharePoint Solution builds with Visual Studio Extensions for Windows SharePoint Services (VSEWSS) 1.3
In this walkthrough, I ' ll demonstrate you to achieve automated builds and continuous integration by creating a builds scrip T for VSEWSS 1.3 solutions. The patterns and Practices SharePoint guidance (one Drop) contains a example build script that this article was based on, But I found some issues with it in practice, I ' d like to share. Before we get started, I ' d as talk about the design of the extensions and some of the problems them.
VSEWSS 1.3 Stores information used to builds the WSP file in a directory named "Pkg" This is isn't included in the PROJECT.&N Bsp This works fine to individual development on a single machine, but the not so. The PKG directory must is manually included in the project so files needed to builds the WSP are included in source control. If You are forget to does this, your teammates won ' t is able to builds the WSP, and you risk losing the deployment con figuration. Furthermore, if you are later add a new feature, you also have manually add the new feature subdirectory to The project. in addition to storing configuration information, the PKG directory is also where solution files (featu Re.xml for example) are automatically generated. if you are package the WSP (or refresh in the WSP view), the files in The PKG directory must is checked out to is re-generated. this also causes on the build server problems the Files in the Pkg DIrectory are read-only because they are checked into source control. a improved design would is to store WSP Config Uration information in a folder/file this is part of the project with the PKG directory only for generating BA Sed on the WSP configuration files. so now, are aware of some of the team development ' Gotchas ' with VSeWSS 1.3, I ' ll show you, step-by-step, how to configure automated builds.
If you are just want to the "build script", get it here. update:get A simplified build script Here .
If you have a installed TFS build, you'll need to install it using the TFS installation media. You'll also need to configure a service account such as TFSBuild, and add the account to the TFS server Group team Found ation licensed Users and the team Project (s) group build Services.
To get started, configure the build agent. In the team project Select Builds > Manage build Agents ...
Enter The build agent properties for your build server
Create a new build definition by selecting builds > New build Definition ...
Enter a name for the build definition
Configure the workspace. Note:all files in the source control folder would be downloaded to the local folder you specify and so is sure the location y Ou specify has enough free spaces
Create the project file (TFSBuild.proj) by selecting the version control folder where you want it stored and selecting Cre Ate...
Select the Visual Studio solution to build and click Next
Select the configuration (s) to build and click Next
If you are want to run unit tests or code analysis during the build, configure it and click Finish
Now, the project file is created, click OK
Configure How many builds your would like to retain and click OK. Note:you should at least keep the latest of failed or partially succeeded-builds or the build log file and need to Troubl Eshoot would be deleted
Enter a share where the build files would be dropped and click OK
Configure what triggers, either manually, on a schedule or when files are checked in (continuous integration)
Test the build by highlighting the "build definition" and selecting Queue New build ...
Click Queue
At I/should have a working build, but it doesn ' t package the wsp file yet
Next, we ll modify the build script to package the WSP file. The build steps are as Follows:clean all workspaces/files left by the previous build packaging build the Visual Stud IO solution Delete The workspace that is created by the builds Create a workspace for the WSP packaging build Open a Secon D instance of the IDE and package the solution using The/package switch Copy the WSP to the Drop folder
In addition to this process, a nice to have are to display the packaging steps the GUI and so we'll use the BuildStep task To accomplish that
To get started, get the latest version of the Team Build Types folder
Check out the TFSBuild.proj file. Note:when developing the build script, you'll have to check it out to work on it, and check it back into test it
Add the custom tasks used by the build. Although we could accomplish what we need to using TF commands, which are the tasks are installed with TFS and work
<project defaulttargets= "Desktopbuild" xmlns= "http://schemas.microsoft.com/developer/msbuild/2003" toolsversion= "3.5" >
<!--These tasks are used by the team build process defined in this file-->
<usin Gtask taskname= "Microsoft.TeamFoundation.Build.Tasks.DeleteWorkspaceTask"
assemblyfile= "$ (Teambuildrefpath) /microsoft.teamfoundation.build.tasks.versioncontrol.dll "/>
<usingtask taskname=" Microsoft.TeamFoundation.Build.Tasks.CreateWorkspaceTask "
assemblyfile=" $ (teambuildrefpath)/ Microsoft.TeamFoundation.Build.Tasks.VersionControl.dll "/>
ADD the variables needed for WSP packaging. Note:there is probably a better way to determine the location of the IDE
<PropertyGroup>
<!--
Variables added for VSEWSS 1.3 builds
-->
<!-- Idepath
The path in which DEVENV and TF reside
-->
<idepath>c:/program files/microsoft Visual Studio 9.0/common7 /ide</idepath>
<!--tempworkspacename
Workspace name, must not match a existing namespace name
-->
<TempWorkspaceName>NightlyBuildTempWorkspace</TempWorkspaceName>
</ Propertygroup>
Add the solution to build. Note:this would build the binaries, but would not generate the WSP file
<ItemGroup>
<solutiontobuild include= "$ (buildprojectfolderpath)/. /.. /intranet/intranet.sln ">
<Targets></Targets>
<Properties></Properties>
</SolutionToBuild>
</ItemGroup>
Add the target to clean up any files left by the previous build packaging (if the previous builds failed or was Cancelle D) . this target are called during the build just before the workspace be created to build the solution
<!--before the build WorkPace is initialized--> <target name= "Beforeinitializeworkspace" > <!-- Delete Temporary workspace (if left by previous build)--> <buildstep teamfoundationserverurl= "$ (Teamfou Ndationserverurl) "builduri=" $ (BuildUri) "message=" Deleting temporary workspace ("$ AME) " (if left by previous build). "
> <output taskparameter= "Id" propertyname= "StepID"/> </BuildStep> <deleteworkspacetask Teamfoundationserverurl= "$ (teamfoundationserverurl)" builduri= "$ (BuildUri)" Name= "$ (tempworks Pacename) "deletelocalitems=" true "/> <deleteworkspacetask teamfoundationserverurl=" $ (TeamF Oundationserverurl) "builduri=" $ (BuildUri) "Name=" $ (tempworkspacename) "deletelocalitems=" FA
LSE "/> <buildstep teamfoundationserverurl=" $ (teamfoundationserverurl) " Builduri= "$ (BuildUri)" Id= "$ (stepid)" status= "succeeded"/> <!--Error OCC urred--> <onerror executetargets= "markbuildstepasfailed"/> </Target>
ADD the error handling target. If any of the other steps fail, they'll call this target using executetargets
<!--Handles Custom errors-->
<target name= "markbuildstepasfailed" >
<buildstep
Teamfoundationserverurl= "$ (teamfoundationserverurl)"
builduri= "$ (BuildUri)"
id= "$ (stepid)"
status= "Failed"/>
</Target>
In the Aftercompile target, add the "step" to delete the workspace this is automatically created by the build
<!--after the solutions are compiled-->
<target name= ' aftercompile ' >
<!--Delete build Workspac E-->
<buildstep
teamfoundationserverurl= "$ (teamfoundationserverurl)"
builduri= "$ (BuildUri)"
message= "Deleting build Workspace "$ (workspacename) "." >
<output taskparameter= "Id" propertyname= "StepID"/>
</BuildStep>
< DeleteWorkspaceTask
teamfoundationserverurl= "$ (teamfoundationserverurl)"
builduri= "$ (BuildUri)"
Name= "$ (workspacename)"
deletelocalitems= "false"/>
<buildstep
teamfoundationserverurl= "$ ( Teamfoundationserverurl) "
builduri=" $ (BuildUri) "
id=" $ (stepid) "
status=
" succeeded "/>" <!--end Delete build Workspace-->
Just below that, add the builds step to create the temporary workspace
<!--Create Temporary workspace--> <buildstep teamfoundationserverurl= "$ (teamfoundationserverurl) "builduri=" $ (BuildUri) "message=" Creating temporary workspace ("$ Rkspacename) ".
> <output taskparameter= "Id" propertyname= "StepID"/> </BuildStep> <createworkspacetask Teamfoundationserverurl= "$ (teamfoundationserverurl)" builduri= "$ (BuildUri)" builddirectory= "$ (builddirectory) "sourcesdirectory=" $ (solutionroot) "Name=" $ (tempworkspacename) "comment=" Te Mporary Workspace "> </CreateWorkspaceTask> <buildstep teamfoundationserverurl=" $ (teamfo Undationserverurl) "builduri=" $ (BuildUri) "Id=" $ (stepid) "status=" succeeded "/&G"
T <!--end Create temporary workspace;
Add the step to package the solution. this is marks all files into the PKG directory as not read only--the Packa Ging'll is able to overwrite this files otherwise. Then it runs the IDE and uses the/package switch to Gener Ate the wsp. Finally, it copies the WSP to the drop folder. If your had multiple WSP files to builds, you could Repeat the steps below or refactor into a target
<!--place projects to package--> <!--builds and package solution--> <buildstep Teamfoundationserverurl= "$ (teamfoundationserverurl)" builduri= "$ (BuildUri)" message= "Packaging " ; Contoso Intranet Solution". > <output taskparameter= "Id" propertyname= "StepID"/> </BuildStep> <!--the extensions mo dify files in the pkg directory, so those files cannot read only--> <exec command= "Attrib-r "$ (Builddi Rectory)/contoso/intranet/deployment/pkg/*.*" /s/d "/> <!--Open A second instance of the dev environment and build using/package switch--> <ex EC command= ""$ (Idepath)/devenv" "$ (builddirectory)/contoso/intranet/intranet.sln" /deploy debug/package "/> <!--Copy to drop location--> <exec command=" xcopy "$ (Builddirec Tory)/contoso/intranet/deployment/bin/debug/contoso.intranet.wsp" "$ (droplocation)/$ (BuildNumber)/" /e/y/R "/> <buildstep teamfoundationserverurl=" $ (teamfoundationserverurl) "Buildu Ri= "$ (BuildUri)" Id= "$ (stepid)" status= "succeeded"/> <!--end Build and package Sol Ution-->
ADD The build step to delete the temporary workspace we created
<!--Delete Temporary workspace-->
<buildstep
teamfoundationserverurl= "$ (teamfoundationserverurl "
builduri=" $ (BuildUri) "
message=" Deleting temporary workspace "$ (tempworkspacename) ". >
<output taskparameter= "Id" propertyname= "StepID"/>
</BuildStep>
< DeleteWorkspaceTask
teamfoundationserverurl= "$ (teamfoundationserverurl)"
builduri= "$ (BuildUri)"
Name= "$ (tempworkspacename)"
deletelocalitems= "false"/>