During development, your team makes a lot of changes to fields, templates, presentation details, and various other elements that need to be tracked, verified, and deployed. You need a way to source control those database changes, and then make them available to your team to test. Here’s how to accomplish that using Team Foundation Server (TFS) and Team Development for Sitecore (TDS)!
Sitecore content items in source control
Our teams use Team Development for Sitecore from Hedgehog Development to create .NET TDS projects to source control the changes we make in the Sitecore database. There’s a great guide from Hedgehog to start with, and I’ve previously written a post on some project configuration basics.
Automating deployments of Sitecore content items
With your content items now in Source Control, you can start getting your database changes deployed along with your build.
Note: This assumes you are automating your file deployments to push code changes out to your environments. If you aren’t yet, you should be! Look for my upcoming posts on setting up deployment build configurations.
In order to get TFS to be able to deploy, there are a few things you need:
- Install TDS. The TDS software needs to be on the TFS build server. Depending on your infrastructure, this may be the same machine that is hosting your source control, or you may be running the build agents on a separate build machine (recommended!) This does not require an additional license to be purchased as Hedgehog allows your build server to be covered under your existing developer licensing. (Check their FAQs for details).
- Configure Build Settings. Your TFS build configuration needs a few parameters in order to ensure the content items are deployed to your review environment.
- SitecoreWebUrl: This specifies the URL of the website you want to update. For example: http://dev.mydomain.com.
- SitecoreDeployFolder: This specifies the UNC path where the Sitecore website folder is located. You should set up a share to push to if the website folder is on a network server separate from the build server (recommended!). For example: //mydevserver/Website
Your build configuration Process section will look something like this:
1. Required 2. Basic 3. Advanced MS Build Arguments /p:IsDesktopBuild=false;GeneratePackage=false;SitecoreWebUrl=http://dev.mydomain.com;SitecoreDeployFolder=”\\mydevserver\Website”
Publishing after deployment
There are several ways to accomplish this, including using Sitecore Rocks, but we have done this by setting up an ASPX on our internal Sitecore sites to execute a publish. The build configuration has an InvokeProcess action with a Powershell call to trigger this. By editing your build configuration template XAML with Visual Studio (or an XML Editor) you can add the InvokeProcess action to execute a Powershell call to the publishing page.
In our template, we use a custom argument named ‘PublishUrl‘ so that we can re-use the templates for multiple deployments and provide the URL to the publishing page in the build configuration. If you are only using the template for a single deployment build configuration, you can replace this custom argument with the explicit value of the publishing page. For example: http://mywebsite/SomePath/Publish.aspx
XAML Configuration – The XML
You can use the workflow process editor to add the InvokeProcess in Visual Studio, or add it directly with the following XML. The template used by the build configuration for TFS uses an additional action after you’ve deployed files and deployed TDS changes. Here is the XML that gets added to your template in order to invoke the URL:
<mtbwa:InvokeProcess Arguments="["&{$r = [System.Net.WebRequest]::Create('" + PublishUrl + "'); $resp = $r.GetResponse();}"]" DisplayName="Publish to website" FileName="powershell.exe">
<mtbwa:InvokeProcess.ErrorDataReceived>
<ActivityAction x:TypeArguments="x:String">
<ActivityAction.Argument>
<DelegateInArgument x:TypeArguments="x:String" Name="errOutput" />
</ActivityAction.Argument>
</ActivityAction>
</mtbwa:InvokeProcess.ErrorDataReceived>
<mtbwa:InvokeProcess.OutputDataReceived>
<ActivityAction x:TypeArguments="x:String">
<ActivityAction.Argument>
<DelegateInArgument x:TypeArguments="x:String" Name="stdOutput" />
</ActivityAction.Argument>
</ActivityAction>
</mtbwa:InvokeProcess.OutputDataReceived>
</mtbwa:InvokeProcess>
Publish.aspx
The code for our Publish page is something like this:
string full = Request.QueryString["full"];
// Set up the publish mode
PublishMode publishMode = PublishMode.Smart;
if (!string.IsNullOrWhiteSpace(full) && (full == "1" || full.Equals("true", StringComparison.InvariantCultureIgnoreCase)) ) {
publishMode = PublishMode.Full;
}
using (new Sitecore.SecurityModel.SecurityDisabler()) {
//We need the target database
var webDb = Sitecore.Configuration.Factory.GetDatabase("web");
//source db
var masterDb = Sitecore.Configuration.Factory.GetDatabase("master");
try {
foreach (Language language in masterDb.Languages) {
//loops on the languages and do a full republish on the whole sitecore content tree
var options = new PublishOptions(masterDb, webDb, publishMode, language, DateTime.Now)
{RootItem = masterDb.Items["/sitecore"], RepublishAll = true, Deep = true};
var myPublisher = new Publisher(options);
myPublisher.Publish();
}
}
catch (Exception ex) {
Sitecore.Diagnostics.Log.Error("Could not publish the master database to the web", ex);
}
}
But I don’t use TFS?
The concepts above can apply to almost any build server, be it Jenkins, TeamCity, or other. I’ve recently posted about how to use TeamCity for Sitecore deployments, and in the future I’ll discuss how to configure this for Jenkins.
Great article. I am about to implement this feature for our Sitecore website and your article is an excellent starting point for that.
Thanks Ben!
Thanks for the great solution.
I am trying to implement your solution but VS 2010 gives me an end of expression error for the InvokeProcess Arguments.
Any help is appreciated.
Hi Goutam, it’s entirely possible it’s a formatting issue on the blog post. The inner quotes and ampersands need to be entered into the XML as " and &
So something like this: ["&{$r = [System.Net.WebRequest]::Create(‘" + PublishUrl + "’); $resp = $r.GetResponse();}"]
If you use the XAML editor in Visual Studio, you can edit the action there and you won’t have to worry about it. You can just copy it in and it will format it for you in the XAML file.
Ok, thanks. I shall try it.
Thank you
Hi Jason,
The bin directory in my deployed website is empty – am I missing a setting?
Chris
Hi Chris, the first thing you should check is to make sure your build server has access to the share folder you’ve set up on your network for your deployed website. The TFS build agent won’t be able to push across the network to your target website unless you provide a shared path to push the files with the appropriate security.
If your bin directory previously had files and after a deploy has lost all content in the bin directory, that is a different issue altogether. The build server itself won’t delete files in the target unless you change your XAML to have actions to erase files from the target.
Hi Jason, the build server has access. Just checked the __PublishedWebsites folder on the build server that everything gets deployed from and the bin directory there is empty too
Chris
If the build server itself does not have any DLLs in the bin directory, that is usually an indication of a failure somewhere in your build process. Have you investigated the build logs? Are your non-DLL files being generated correctly into the _PublishedWebsites folder? Do your Build Defaults in the build configuration have a drop-folder specified?
Hi Jason, the logs seem fine – no errors. It’s just that the TDS project doesn’t seem to build the dependent web project. In the build definition, do you set the project to build to the whole solution, or just the TFS project?
Chris
Hi Chris, we set our workspace setting on the build definition to pull down the whole branch. The process section then builds the solution so that the TDS projects and the rest of the website all build.
Projects to Build: $/MyTFSProject/MyBranch/MySolution.sln
Got it working now – thanks for your help. I’d specified only the TFS project to build, thinking it would build all dependent projects – D ‘Oh
Hi Jason – very good article indeed. I’m trying to setup the same scenario with our sitecore project, and I had a few architectural questions:
1. I already have a build template for sitecore that doesn’t include TDS. So adding TDS in there, do I not build by web project anymore? Do I only build the TDS project? Do the msbuild option only apply to the TDS project?
2. In the build template, do I build the TDS project(s) or the whole solution?
3. What happens if I have more than 1 TDS project – i.e. a TDS project for master db and another one for core db
Another one to add on top of this. For the TDS project, I have to put a deploy folder so that it can install the connector – and that has to be the web folder on the server. The issue that I see is two-fold:
1. I don’t neccesarily want TDS to push the code onto the server directly – not sure what the ramifications are exactly – the TFS build templates don’t do this automatically, they just put it in the drop folder – however, I can’t point the TDS project to the DROP folder,because then it can’t install the connector
2. What happens if I have more than 1 QA server….
Any ideas?
For your follow-ups:
1. Manual deployments? If you don’t want to use automated deployments, you don’t have to. There is a build configuration option for ‘Deploy’ that you can disable. The TDS project properties also have an ‘Update Package’ tab that allows you to configure package generation during the build. This can be specific per build configuration so that you don’t generate packages during normal development, but can during your TFS build. That way you can install the packages manually using the package installation wizard at sitecore/admin/UpdateInstallationWizard.aspx
2. Multiple servers? If all your QA servers are pointed at the same database, it doesn’t really matter. You just install the package once (or just deploy directly to the database once). All of your content delivery nodes will get the same data.
I’ll start with your initial questions first Mickey:
1. Reuse build template? If your build template is building the whole solution, then inclusion of the TDS projects should be based on whether you include the projects in the Build Configuration being used. TDS projects also have a ‘Deploy’ option in the Build Configuration, which you can choose to use or not.
2. Build all? I advise building everything. Your website and the TDS projects.
3. Multiple projects? We always have one for Core and one for Master. If the projects are both in the Build Configuration for the solution, they both get built.
Thanks Jason, for the response!
So – I’m confused as to how from the build process the templates and sitecore items end up in the targeted environment? Do you have to point the “Sitecore Deploy Folder” directly to the IIS web folder on the target environment, and then it will install via the TDS service (connector)?
The Sitecore Web URL specifies the location that TDS should connect to for talking to the web service. The Sitecore Deploy Folder specifies where it should install the connector. These usually map to the same root directory of the target website being updated.
As you surmised, when the build actions occur on a TDS project, it uses the TDS software installed on the build server to know how to talk to the connector. It then figures out WHAT needs to be sent based on the project definition, then uses the configuration to figure out WHERE to send it, and then begins the transmission of the serialized data over to the website.
Jason, I guess my question – I want TDS to deploy the sitecore items, but not the code dlls – is that possible?
The TDS options for Sitecore Deploy Folder and Sitecore Web URL only apply to the TDS projects, so only affect content. They don’t affect your code. Your code still follows the standard build template configurations you’ve setup for MSBuild. If you don’t create a build step in your build template to copy the published code files to the target destinations, then the code won’t transmit.
I don’t personally recommend that, however, as it will mean that you may deploy content changes, or new template changes, that are not compatible with the code that is running on the website. This would put your application out of sync.
Hi Jason,
As part of continuous deployment, I am using TFS 2012. I created a build definition with the following parameters and working fine without TDS project.
/p:DeployOnBuild=True /p:DeployTarget=MsDeployPublish /p:CreatePackageOnPublish=True /p:MSDeployPublishMethod=InProc /p:AllowUntrustedCertificate=True /p:MSDeployServiceUrl=”https://WIN-ABC:8172/msdeploy.axd” /p:DeployIisAppPath=”TestSite” /p:username=”domain\Administrator” /p:password=Password123
however, when i add TDS project, it Failed giving me the following error.
“The build output path must be relative to the TDS project root.”
Like you said above, When i include SitecoreWebUrl= “…” SitecoreDeployFolder=”…”,
the build itself failed. Can you please let me know clearly, what special things i need to do when i have TDS project in my solution. Thanks a LOTTTTTTTTTTT if you could help me by tomorrow.
Narasimha, if you need immediate support, the Hedgehog folks who make TDS provide great email support. Just send an email to: support@hhogdev.com
Based on the information you have, I can’t be sure what the issue is. Have you configured your TDS projects for building yet? Do you have settings on the project for the build configuration you are deploying? What error do you get when including the SitecoreWebUrl and SitecoreDeployFolder build settings?
Hi Jason,
Thanks for the quick reply and suggestion.
I am able to configure TDS Project and able to ‘get items’ and ‘sync items’. The problem is only in “Continuous deployment”. I am successful in creating the build definition and triggering build when the solution has no TDS project. but after adding it my build is not working. I just need what special things I should do when we have a tds project in the solution. when i added the above two parameters related to sitecore in my build, I got the below for both params
MSBUILD : error MSB1008: Only one project can be specified.
Switch: SitecoreWebUrl=http://sitecoreemptestwebsite/
Narasimha, if you remove your other build arguments and only put in the TDS arguments, do you still get the error? Also, is your build triggering at the solution level, or have you selected your Website project as the build? Finally, have you gone through the guide provided by Hedgehog to see if there is anything amiss with your build configuration?
Hi Jason, Thanks for the reply.
I tried removing other build args and keeping only TDS args but faced some other error.
I am doing the build at solution level. That means all website project, class library kind of projects like test projects and TDS project everything under one solution and that solution is considering for the build. I am using MsDeploy tool for deploying at the target location. I have the TDS project problem only in build. I am able to get and sync sitecore items.
Please let me know for additional information.
hi jason,
I came to know from hedgehog that this is a tds error and they sent me below message.
In order to avoid this error, a line inside the TDS .targets file, which checks the output directory, needs to be commented out. Assuming that you have already TDS installed on your build server, the .targets file is located at “C:\Program Files (x86)\MSBuild\HedgehogDevelopment\SitecoreProject\v9.0\HedgehogDevelopment.SitecoreProject.targets”.
Thanks for your time.
Hello Jason,
Great article! Thumbs up.
However, I have a little issue. I use Jenkins and really needs the steps to configure TDS to automate the deployment of the differnt packages. Can you shed some light please.
Thanks
Faldeen
Hello Faldeen, thanks for reading! Unfortunately, I have not personally had a chance to play around with Jenkins to get full details on it. However, I may be able to get you started on the right path.
I have written up steps for how to deploy with TeamCity, which employs a somewhat similar conceptual framework to Jenkins in many respects. At least, it’s much closer than TFS. Read it here:
https://theagilecoder.wordpress.com/2013/01/12/automating-sitecore-deployments-with-teamcity-and-tds/
From my understanding, you can configure your Jenkins to use an “MSBuild” step. The core of getting TDS to deploy content is configuring the MSBuild arguments that are sent to your solution. If you create your Jenkins build configuration with an MSBuild step and then use the MSBuild arguments shown in the TeamCity configuration, you should be good to go.
Hello Jason,
Many thanks for your prompt reply.
I will used the steps and try to play with Jenkins. I will give you and an update soon.
Regards,
Faldeen
Hey Jason- Is there any video out there that we can see? I am fairly new to TDS and TFS and would like to see it in action.
RJ
Hi there, RJ. If you are starting into Sitecore and looking at Team Development for Sitecore (TDS), you might want to check out Hedghog’s TDS channel on Youtube: https://www.youtube.com/playlist?list=PLb9QmtmxCbhl1uzG_XJ37Sc9fhsJNLfaM
Team Foundation Server (TFS) and its cloud-option Visual Studio Online (VSO) are Microsoft products that have a ridiculous number of videos. For example, here is one of Microsoft’s introduction videos for VSO: https://www.youtube.com/watch?v=OVqJJxC9IRU
I have also shown a little tiny bit of TDS in action with Team City during my presentation at the 2015 SUGCON in North America: https://www.youtube.com/watch?v=qXWC7l3d7zE