True Delta Deploys with TDS Classic
TDS (now TDS Classic) 5.5 introduced a feature called ‘Delta Deploy’ where the deployment of your project, either in development (using the Sitecore Connector) or in update packages, had the ability to ‘skip’ items assuming that they’ve already been deployed.
By default, we needed to build this feature in a way that was agnostic of source control provider (Git, TFS, SVN), and agnostic of source control strategy (main-line dev, Git Flow, Github Flow etc)…but extensible, so that teams could develop their own logic for their own project.
The default implementation allows users to specify a date in the ‘Deploy Items Changed After’ field on the General Properties tab.
This is saved into the scproj file as something like:-
Then, during a deployment (either local, remote or Update package construction) TDS will assess every item in the project, and skip items that have not been updated since that date (i.e it checks the __Updated field on the .item file).
Furthermore, as stated by my colleague Derek Hunziker on this StackExchange post, you can make this a rolling date…. as in ‘items updated in the last week’ by entering a dynamic date.
Update: This is now available as a feature in TDS Classic 5.7, where on the General Properties page, you either have the option to select a fixed ‘date since’ date, or a number of days since X amount of days.
Effective this is the same thing as above, because the UI just now saves the same string above into the scproj file.
Or, if you’re triggering this through MSBuild, you would take Derek Dysart‘s recommendation by using the parameter ‘IncludeItemsChangedAfter’ in the call to MSBuild. (notice the parameter name matches the name of the node in the scproj).
MSBuild.exe MySolution.sln /p:IncludeItemsChangedAfter=2016-04-06;Configuration=Release /t:Rebuild
Great! So what’s the problem?
As I mentioned…. the default check by TDS uses the __Updated field on each .item file. But consider what this might mean for a branching source control strategy like Git Flow.
If there was, say, a long running feature branch, where a developer had pulled in items from Sitecore a month ago…. but the main-line development had done a couple of releases from the master branch in that time….
If the date we pass to the TDS build is simply ‘the date since the last deployment’….that might only be 1 week ago.
Now when that long-running feature branch is merged into the main-line….it will include .item files that say they were updated 3 or 4 weeks ago….. then our next deployment that only takes items ‘Updated’ in the last week would skip these items…..and now we have issues on our Sitecore instance due to the missing items.
OK, let’s increase the Delta Date
In some cases, I’ve seen teams opt for the brute case….saying ‘well, we’ll just make that date bigger, and hopefully encompass all changes across all branches’. For example, in the above, the ‘delta date’ could be increased to 2 months…. and would therefore include the feature branch changes. That’s fine….but it also means you’re probably redeploying a lot of other items too. It works, and it still saves you time….but it’s still not a ‘true’ delta.
Customize and Revolutionize
As I mentioned, this feature is customizable….On StackExchange Mike Edwards asked how this could be done. My answer gives a generic example for how developers would like this to work…. but I recently went to implement it for a project using Git.
Here’s how it works. In my module, we save a LastDeploymentGitCommitID.txt file in the project’s ‘Report’ folder. (I use this because this is where we output the new Project Item Reports if they’re used).
This txt file, as the name suggests, stores the Git commit ID of the last (successful) deployment made by the TDS project.
For the next deployment, we may have grabbed the latest changes from other developers from Git, so we’re now a couple of commits ahead of where we were previously. We grab the current Git Commit ID, and check it against the last deployment commit ID. Before actually doing the deployment, we do a git diff to get the changed .item files since then, and save them to a /Report/ChangedItemFiles.txt file for auditing.
Then we overwrite the ‘CullItemsFromProjectClass‘ with our own custom code, that checks each .item file in the project to see if it is mentioned in our list. If it exists in our list in ChangedItemFiles.txt, then we know it’s been added/edited since our last TDS deployment, and so it is ‘deployable’ in our delta deploy. If not, we can assume it was already pushed, so we can skip it.
We then re-save the LastDeploymentGitCommitID.txt file with the ‘new’ current Git commit ID….so the next deployment can again ‘trim the fat’.
The result of this is ‘True’ Delta deployments….based on what’s actually changed in source control. This will work for git pulls, as well as branch switching, and has greatly improved the performance of the deployment and given us a reliable delta deploy as well.
How can I get it?
In your TDS project, simply consume the Hedgehog.TDS.BuildExtensions.GitDeltaDeploy NuGet package (available on nuget.org), then (if you’re not using the HedgehogDevelopment.TDS main NuGet package) copy the tools/Hedgehog.TDS.BuildExtensions.GitDeltaDeploy.dll file to your local Hedgehog MSBuild folder (C:\Program Files (x86)\MSBuild\HedgehogDevelopment\SitecoreProject\v9.0). (if you’re using the HedgehogDevelopment.TDS main NuGet package, the build will attempt to copy the DLL where it needs it itself).
To turn it on, add
to your TdsGlobal.config.user file (under the PropertyGroup for the Debug Configuration).
Close and reopen Visual Studio, and run your first deployment…. then following deployments will be a proper delta from the previous one.
If you want this to run via a call to MSBuild, just remember to include the parameter CustomGitDeltaDeploy=True. And, if you want to pass in the ‘last deployment commit id’ (because maybe you have another way of storing it) then pass in the parameter LastDeploymentGitCommitID=SOME_GUID_THAT_IS_A_GIT_COMMIT_ID.
The code is shared at this Github repository.
Let me know what you think.