However, with this great flexibility the issue arises on how to move the metadata (composer templates) between environments. For instance, how do I ensure all my developer machines have the same templates and the correct version of those templates. There is also the issue of moving new entity fields to Test and Production environments.
The other way to do this will be to serialize the composer templates to JSON and bring them in again in the destination environment. Detailed here is my preferred approach for projects where you have templates that will change often (in Agile projects this is common of course) , many templates and many developers i.e. a large complex project.
The code first approach to composer template deployment outlined here, follows the premise that templates are created and managed in code. Therefore they can be version controlled and history can be tracked in Git or elsewhere along with all your other code.
Developer flow :-
- Developer A writes the code to create the composer template.
- The engine code is checked in by Developer A
- Developer B gets the latest code.
- Developer B runs the API command in the engine via postman manually to create the composer templates in his environment. This could also be automated.
- Developer B runs “update templates” function in Sitecore.
Deploy to Test or Prod flow :-
- Developers create and update composer templates via code in the commerce engine
- End of sprint build is created
- Commerce engine build is deployed to environment
- The API command in the engine is run manually or through automated mechanism to create composer template
- “Update templates” function is run in Sitecore. (Can be automated)
The following code is a commerce engine plugin that can be used as a template…well to create your templates 🙂
It is made up of the following components :-
- New pipeline and pipeline block, the code responsible for creating the templates via code.
- New API command, this command exposes the create composer templates via the engine so it can be called manually or through an automated build process.
Step 1 – Create new plugin
The command in this plugin, when run, will create a new template called “DiscontinuedTemplate” with one boolean field called “Discontinued”. The new template will be assigned to all “Refridgerator” sellable items (Product definition)
- In the Commerce Engine SDK create a new plugin and reference it from the engine
- Add the following code to create the pipelines
In folder “Pipelines” create…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Services.Examples.Composer | |
{ | |
using Sitecore.Commerce.Core; | |
using Sitecore.Framework.Pipelines; | |
[PipelineDisplayName("CreateComposerTemplatesPipeline")] | |
public interface ICreateComposerTemplatesPipeline : IPipeline<CreateComposerTemplatesArgument, bool, CommercePipelineExecutionContext> | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Commerce.Plugin.Sample | |
{ | |
using Microsoft.Extensions.Logging; | |
using Sitecore.Commerce.Core; | |
using Sitecore.Framework.Pipelines; | |
using Sitecore.Services.Examples.Composer; | |
public class CreateComposerTemplatesPipeline : CommercePipeline<CreateComposerTemplatesArgument, bool>, ICreateComposerTemplatesPipeline | |
{ | |
public CreateComposerTemplatesPipeline(IPipelineConfiguration<ICreateComposerTemplatesPipeline> configuration, ILoggerFactory loggerFactory) | |
: base(configuration, loggerFactory) | |
{ | |
} | |
} | |
} |
In folder “Pipelines\Arguments” create…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Services.Examples.Composer | |
{ | |
using Sitecore.Commerce.Core; | |
using Sitecore.Framework.Conditions; | |
public class CreateComposerTemplatesArgument : PipelineArgument | |
{ | |
public CreateComposerTemplatesArgument(object parameter) | |
{ | |
Condition.Requires(parameter).IsNotNull("The parameter can not be null"); | |
this.Parameter = parameter; | |
} | |
public object Parameter { get; set; } | |
} | |
} |
In folder named “Pipelines\Blocks” create…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Services.Examples.Composer | |
{ | |
using System; | |
using System.Threading.Tasks; | |
using Sitecore.Commerce.Core; | |
using Sitecore.Framework.Conditions; | |
using Sitecore.Framework.Pipelines; | |
using Sitecore.Commerce.Plugin.Composer; | |
using Sitecore.Commerce.Plugin.ManagedLists; | |
using Sitecore.Commerce.Plugin.Views; | |
using Sitecore.Commerce.EntityViews; | |
using System.Collections.Generic; | |
[PipelineDisplayName("CreateComposerTemplatesBlock")] | |
public class CreateComposerTemplatesBlock : PipelineBlock<SampleArgument, bool, CommercePipelineExecutionContext> | |
{ | |
private readonly CommerceCommander _commerceCommander; | |
public CreateComposerTemplatesBlock(CommerceCommander commerceCommander) | |
{ | |
_commerceCommander = commerceCommander; | |
} | |
public override async Task<bool> Run(SampleArgument arg, CommercePipelineExecutionContext context) | |
{ | |
Condition.Requires(arg).IsNotNull($"{this.Name}: The argument can not be null"); | |
//Create the template, add the view and the properties | |
string templateId = $"{CommerceEntity.IdPrefix<ComposerTemplate>()}{"DiscontinuedTemplate"}"; | |
var composerTemplate = new ComposerTemplate(templateId); | |
composerTemplate.GetComponent<ListMembershipsComponent>().Memberships.Add(CommerceEntity.ListName<ComposerTemplate>()); | |
composerTemplate.LinkedEntities = new List<string>() { "Sitecore.Commerce.Plugin.Catalog.SellableItem" }; | |
var itemDefinitions = new Sitecore.Commerce.Plugin.Catalog.ItemDefinitionsComponent | |
{ | |
Definitions = new List<string>() { "Refrigerator" } | |
}; | |
composerTemplate.Components.Add(itemDefinitions); | |
composerTemplate.Name = "DiscontinuedTemplate"; | |
composerTemplate.DisplayName = "Discontinued Template"; | |
var composerTemplateViewComponent = composerTemplate.GetComponent<EntityViewComponent>(); | |
var composerTemplateView = new EntityView | |
{ | |
Name = "Discontinued", | |
DisplayName = "Discontinued", | |
DisplayRank = 0, | |
ItemId = $"Composer-95DACDDD-151E-4527-9068-A27C9275967F", | |
EntityId = composerTemplate.Id | |
}; | |
composerTemplateView.Properties.Add(new ViewProperty() { DisplayName = "Discontinued", Name = "Discontinued", OriginalType = "System.Boolean", RawValue = false, Value = "false" }); | |
composerTemplateViewComponent.View.ChildViews.Add(composerTemplateView); | |
var persistResult = await this._commerceCommander.PersistEntity(context.CommerceContext, composerTemplate); | |
return await Task.FromResult(true); | |
} | |
} | |
} |
- Add the following code to be able to execute the code externally via the API
In folder “Commands”…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Services.Examples.Composer | |
{ | |
using System; | |
using System.Threading.Tasks; | |
using Sitecore.Commerce.Core; | |
using Sitecore.Commerce.Core.Commands; | |
using Sitecore.Commerce.Plugin.Sample; | |
public class CreateComposerTemplatesCommand : CommerceCommand | |
{ | |
private readonly ICreateComposerTemplatesPipeline _pipeline; | |
public CreateComposerTemplatesCommand(ICreateComposerTemplatesPipeline pipeline, IServiceProvider serviceProvider) : base(serviceProvider) | |
{ | |
this._pipeline = pipeline; | |
} | |
public async Task<bool> Process(CommerceContext commerceContext, object parameter) | |
{ | |
using (var activity = CommandActivity.Start(commerceContext, this)) | |
{ | |
var arg = new CreateComposerTemplatesArgument(parameter); | |
var result = await this._pipeline.Run(arg, new CommercePipelineExecutionContextOptions(commerceContext)); | |
return result; | |
} | |
} | |
} | |
} |
In folder “Controllers”…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Services.Examples.Composer | |
{ | |
using System; | |
using System.Threading.Tasks; | |
using System.Web.Http.OData; | |
using Microsoft.AspNetCore.Mvc; | |
using Sitecore.Commerce.Core; | |
public class CommandsController : CommerceController | |
{ | |
public CommandsController(IServiceProvider serviceProvider, CommerceEnvironment globalEnvironment) | |
: base(serviceProvider, globalEnvironment) | |
{ | |
} | |
[HttpPut] | |
[Route("CreateComposerTemplatesCommand()")] | |
public async Task<IActionResult> CreateComposerTemplatesCommand([FromBody] ODataActionParameters value) | |
{ | |
var command = this.Command<CreateComposerTemplatesCommand>(); | |
var result = await command.Process(this.CurrentContext, "Placeholder"); | |
return new ObjectResult(command); | |
} | |
} | |
} |
- Add the following to tell the engine about your new commands and pipelines
In the root of your project add…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Commerce.Plugin.Sample | |
{ | |
using System.Reflection; | |
using Microsoft.Extensions.DependencyInjection; | |
using Sitecore.Commerce.Core; | |
using Sitecore.Framework.Configuration; | |
using Sitecore.Framework.Pipelines.Definitions.Extensions; | |
using Sitecore.Services.Examples.Composer; | |
public class ConfigureSitecore : IConfigureSitecore | |
{ | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
var assembly = Assembly.GetExecutingAssembly(); | |
services.RegisterAllPipelineBlocks(assembly); | |
services.Sitecore().Pipelines(config => config | |
.AddPipeline<ICreateComposerTemplatesPipeline, CreateComposerTemplatesPipeline>( | |
configure => | |
{ | |
configure.Add<CreateComposerTemplatesBlock>(); | |
}) | |
.ConfigurePipeline<IConfigureServiceApiPipeline>(configure => configure.Add<Services.Examples.Composer.ConfigureServiceApiBlock>())); | |
services.RegisterAllCommands(assembly); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Sitecore.Services.Examples.Composer | |
{ | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.OData.Builder; | |
using Sitecore.Commerce.Core; | |
using Sitecore.Commerce.Core.Commands; | |
using Sitecore.Framework.Conditions; | |
using Sitecore.Framework.Pipelines; | |
[PipelineDisplayName("SamplePluginConfigureServiceApiBlock")] | |
public class ConfigureServiceApiBlock : PipelineBlock<ODataConventionModelBuilder, ODataConventionModelBuilder, CommercePipelineExecutionContext> | |
{ | |
public override Task<ODataConventionModelBuilder> Run(ODataConventionModelBuilder modelBuilder, CommercePipelineExecutionContext context) | |
{ | |
Condition.Requires(modelBuilder).IsNotNull($"{this.Name}: The argument cannot be null."); | |
var configuration = modelBuilder.Action("CreateComposerTemplatesCommand"); | |
configuration.Parameter<string>("Id"); | |
configuration.ReturnsFromEntitySet<CommerceCommand>("Commands"); | |
return Task.FromResult(modelBuilder); | |
} | |
} | |
} |
Your solutions should look like this…
Step 2 – Run
- Go to Postman and run https://{{ServiceHost}}/{{ShopsApi}}/CreateComposerTemplatesCommand
- Go to the business tools and ensure that your template is created.
- Go to a sellable item and set the discontinued flag to true.
- Go to Sitecore and on commerce tab, hit the update templates button
- Open the item from step 3 in the content editor, you should see the discontinued field checked.
I suppose you did not mean to use SampleArgument, but rather CreateComposerTemplatesArgument
LikeLike
Yep, correct man.
LikeLike