Recently, I caught sight of a discussion in Sitecore Slack where the lack of tooling for helping you build config patch files came up. For some reason that struck a chord with me, and having mulled over it a bit, I decided I'd have a go at making something to see if it could be done...
Having spent a Sunday afternoon doing a bit of hacking, I tweeted an animation of my hacky code in action, and it seemed to strike a nerve with the community. Clearly there are a lot of people who fancy having some tooling for helping with patches...
So to keep you all happy, I've put some more hours into the code, and have posted my "PatchMaker" experiment on GitHub for you all to
tear apart my hacky code
enjoy.
The current release is available here: https://github.com/jermdavis/PatchMaker/releases
Grab the source if you want: https://github.com/jermdavis/PatchMaker.
And raise bugs if you find any issues.
Read on for info and explanations...
At this point the tool allows you to open an XML file, and then click nodes in the tree to create patching instructions to change the selected element or its surroundings. Key features include:
patch:instert
,
patch:instead
,
patch:delete
,
patch:attribute
and
set:attribute
.It's built against .Net Framework 4.7.2 – so you'll need that installed to run it.
For licensing reasons the releases for this on GitHub can't include the Sitecore DLL necessary for previewing the effect of your patches. The app will run happily without that DLL – but the preview option will be disabled. (The button is greyed out, and there's a message in the status bar at the bottom of the main window) You'll need to add your own copy of
Sitecore.Kernel.dll
to the app's directory if you download it this way. (It's built against v8.2 because that had a NoReferences package and I was too lazy to work out how to achive that with a newer version. Other versions will probably work with a version redirect in the app.config) Alternatively, if you clone the source and build your own copy it will use NuGet to fetch this dll for you.
Plus, this is by no means the only way you can approach making patch files. Kamruz Jaman, who was part of the original discussion about patching UI that inspired me is working on his own approach as a web-based tool. And Mikael Högberg mentioned his approach in the twitter thread about all this. You might find you prefer that...
public class PatchInstead : BasePatch { public string XPathForParent { get; } public string XPathForReplacement { get; } public XElement Replacement { get; } }
These have a constructor, which sets up these values, and they implement a method which can construct the correct XML for the patch based on the source XML document, and these properties:
public override void ApplyPatchElement(XDocument sourceXml, XDocument patchXml) { var targetElement = sourceXml.SafeXPathSelectElement(XPathForParent); if (targetElement == null) { throw new PatchException(nameof(PatchInstead), XPathForParent, nameof(XPathForParent)); } var newElement = new XElement(Replacement); newElement.Add(new XAttribute(Namespaces.Patch + "instead", XPathForReplacement)); var currentPatchNode = base.CopyAncestorsAndSelf(targetElement, patchXml.Root); currentPatchNode.Add(newElement); }
In general these methods are constructing the tree of ancestor elements, and then applying the right patch-namespace attributes and elements to match Sitecore's schema.
The
PatchGenerator.cs
class can take a source XML document and a set of these patch definitions, and combine them to give you the patch XML file. This is basically just generating the right root element, and then iterating each patch you defined to call
ApplyPatchElement()
.
These classes were mostly built up using sort-of-TDD, so there are tests for them in the
PatchMaker.Tests
project. They're not exhaustive – but they've helped me catch a few bugs.
The UI for the tool is defined in the
PatchMaker.App
project. It's a basic Windows Forms app – mostly because I coudn't be bothered with the level of googling I would have needed to build it in WPF...
The main window is
PatchPlanningForm.cs
. This defines the XML tree view and the patch listing view that dominate the window, and wire up the assorted menus. When you click to load an XML file, it will parse a representation of the XML into the tree view. The
TreeNode
s have text for the element name and attributes, to give a visual reference of what you're working with. They also map the nodes'
Tag
property to the original
XElement
- as that raw data is used elsewhere.
Each of the patch types is managed by a window defined in the
PatchForms
folder. Both the attribute patches are managed by the same form, as their only difference is how the patch is rendered as XML. Insert, Delete and Instead (replace) get their own forms. Each of these shows you the context node and its ancestors as a visual reference. And it presents fields for filling in the properties of the models mentioned above. For example, the
patch:insert
window looks like:
Some fields are marked as required. Elements which take XML-text will validate the text, and present errors in a balloon tip. You can't accept the form when there are validation errors.
When you hit "ok" to close the form, an instance of the appropriate patch model is created and added to the on-screen list. You can double click the list to edit items, and right-click them do sort, edit and delete.
When you click the menu option to generate the patch file, the UI calls all the
PatchGenerator
class to process the patches you've defined, and displays the results for you:
This text is editable, if you want to add comments or tweak the results – but it's validated, so you can't have bad XML. You can click to save, or you can preview what happens when the patch is applied over the XML you started from. Since that uses Sitecore's own code to process the patch, it should be an accurate reflection of what your patch will do. (But note caveates above about patch file order, and the Sitecore DLL necessary for this code)
↑ Back to top