29 March 2014

Package Installation


Packages, Packages...
A colleague of mine ask me a question about installing packages today. And I wanted to post about the different options available when installing packages. The source of the information describe are from a great post by Martijn Van Der Put.

So when you are installing a package you will have the following screen - if the package is installing items present in the current content tree:


Well the best description for those options are (Thanks Martjin):

Overwrite  Items with the same ID (along with it's descendants) will be removed and replaced by items from the package. 
Skip Items with the same ID from the target database will remain unchanged; the item from the package will be skipped.
Merge - Clear all existing versions for a language of the item being installed are removed prior to adding new versions. This options 'clears out' the versions of the language and creates one new version.
Merge - Append item versions from the package are added 'on-top' of the existing versions of the item. This preserves history, but numbers the package versions with numbers higher than the existing version numbers. A user can merge information between versions afterwards.
Merge - Merge if there is a version with the same number in the item, the Installation Wizard will overwrite it, otherwise a new version with the specific number is added. This makes it possible to replace specific versions of items.


So the important thing here is: If you create a package with the homepage only to do some update and you select overwritte then your entire content tree will be deleted...

19 March 2014

Solution version number accross multiple projects


On this post, I wanted to talk about version number. Most of our solution contains multiple projects and modifying the version number on multiple project is never the great.




So one of the solution could be to have a SharedAssemblyInfoFile which will be used across all the projects.

To do that, the first thing will be to create a File SharedAssemblyInfo.cs file on your main project - the project containing your sitecore files: Views...


Here is the content of the SharedAssemblyInfoFile:
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: AssemblyCompany("My Company")]
[assembly: AssemblyCopyright("Copyright ©  2014")]
[assembly: AssemblyTrademark("")]
// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Revision and Build Numbers 
// by using the '*' as shown below:
[assembly: AssemblyVersion("0.0.0.1")]
[assembly: AssemblyFileVersion("0.0.0.1")]

You can then create a link to an exsiting item for all the other project:

 When adding the existing item, do not forget to select add as link:


Once added, you can move the .cs into the property folder:






Now all your project assembly number will be updated in noe place under your main project...



10 March 2014

Install .update package through an ASHX

Well, today I played a bit with TDS, adding configuration for our Internal QA environment, UAT and Prod (Authoring and Delivery). And this got me thinking on how I could install those packages automatically without having to go through the /sitecore/admin/updateinstallationwizard.aspx

So what I wanted to do is:
  • Create an ashx that will install my packages
  • Create a schedule tasks in sitecore, so I don't even have to trigger this ashx 
Awesome, let's get started

1- The Handler

So the idea is to dump the update packages on a folder. the scheduled task will watch this folder and install the packages when any... So for this exercise we will just say that the folder to watch will be:
/sitecore/admin/Automated_Packages

So let's create our ashx.

the first thing you want to do is to get the list of files on the specific folder:

            var files = Directory.GetFiles(Sitecore.MainUtil.MapPath("/sitecore/admin/Automated_Packages"), "*.update", SearchOption.AllDirectories);


The next step will be to Install the different packages when found. So inside the Foreach loop going through all the files you can execute the following code. This shows you how to use the UpdateHelper to install the package file:

        protected string Install(string package)
        {
            var log = LogManager.GetLogger("LogFileAppender");
            string result;
            using (new ShutdownGuard())
            {
                var installationInfo = new PackageInstallationInfo
                {
                    Action = UpgradeAction.Upgrade,
                    Mode = InstallMode.Install,
                    Path = package
                };
                string text = null;
                List entries = null;
                try
                {
                    entries = UpdateHelper.Install(installationInfo, log, out text);
                }
                catch (PostStepInstallerException ex)
                {
                    entries = ex.Entries;
                    text = ex.HistoryPath;
                    Sitecore.Diagnostics.Log.Error("Deployment error " + ex.StackTrace, "Automated deployment");
                    throw;
                }
                finally
                {
                    UpdateHelper.SaveInstallationMessages(entries, text);
                }

                result = text;
            }

            return result;
        }

After your packages have been installed, what you may want to do is to actually publish your changes to make sure all gets pushed to the delivery server. As our packages usually include only templates, layout, renderings, and some System items we could use something like the following to publish our content - the other way is to republish the entire site - I put both in the same method so you can choose which one is more suitable.
        protected static void Publish()
        {
            Sitecore.Context.SetActiveSite("shell");
            using (new SecurityDisabler())
            {
                DateTime publishDate = DateTime.Now;
                Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
                Sitecore.Data.Database web = Sitecore.Configuration.Factory.GetDatabase("web");

                // publish specific section - Need to  put those in settings
                ID templateFolderID = new ID("{3C1715FE-6A13-4FCF-845F-DE308BA9741D}");
                ID layoutFolderID = new ID("{EB2E4FFD-2761-4653-B052-26A64D385227}");
                ID systemFolderID = new ID("{13D6D6C6-C50B-4BBD-B331-2B04F1A58F21}");

                PublishManager.PublishItem(master.GetItem(templateFolderID), new Database[] { web }, LanguageManager.GetLanguages(master).ToArray(),true,false);
                PublishManager.PublishItem(master.GetItem(layoutFolderID), new Database[] { web }, LanguageManager.GetLanguages(master).ToArray(), true, false);
                PublishManager.PublishItem(master.GetItem(systemFolderID), new Database[] { web }, LanguageManager.GetLanguages(master).ToArray(), true, false);
                
                // republish entire site - not sure if we want granular publish or full republish
                // PublishManager.Republish(Sitecore.Client.ContentDatabase, new Database[] { web }, LanguageManager.GetLanguages(master).ToArray(), Sitecore.Context.Language);
            }
        }