blipson89 / Leprechaun

A template code generation framework for Rainbow
MIT License
42 stars 22 forks source link

Multiple Leprechaun configurations in a SCS JSON file #55

Open Ryanh95 opened 2 years ago

Ryanh95 commented 2 years ago

Good morning,

I am currently in an upgrade from Sitecore 8.2 to 10.2, with leprechaun in use. We used it for model generation but also to generate builders to supplement unit tests, coming from a Unicorn background in 8.2. We basically just did this with a CodeGen file in the test project as well.

We are moving to SCS over Unicorn and now that the Serialization and Generation configs are tied together, is it possible to provide multiple generation configurations per serialization configuration?

Thanks, Ryan

blipson89 commented 2 years ago

Hi @Ryanh95,

That is a very interesting use case. What exactly do these builders look like? Could you provide an example? I have a couple possible ideas, but I'm not entirely sure I understand what the expected output is.

Thanks, Ben

Ryanh95 commented 2 years ago

Hi Ben,

So, for a simple template Sample Item with basic fields Title and Description, Leprechaun would generate something like the following glass model according to our template (note: We use proxy classes):

public interface ISampleItem : IBaseGlassModel
{
    public string Title { get; set; }
    public string Description { get; set; }
}

We also have a different template to generate a custom builder class for a model, using Moq, for unit test purposes which will look something like this;

public class SampleItemBuilder : GlassModelBuilder<ISampleItem, SampleItemBuilder>
{
    private string _title;
    private string _description;

    public SampleItemBuilder WithTitle(string title)
    {
        _title = title;
        return this;
    }

    public SampleItemBuilder WithDescription(string description)
    {
        _description = description;
        return this;
    }

    public ISampleItem Build()
    {
        //Get the base model built from Moq for base properties (related to IBaseGlassModel)
        var model = base.BuildModelMock();

        model.Setup(x => x.Title).Returns(_title);
        model.Setup(x => x.Description).Returns(_description);

        return model.Object;
    }
}

In Sitecore 8.2 we did this by having 2 Leprechaun configurations, e.g;

<configuration name="Sample.Feature" abstract="true">
      <codeGenerator scripts="$(configDirectory)\Foundation\Leprechaun\code\CodeGen\GlassMapper.csx"
                     outputFile="$(configDirectory)\$(layer)\$(module)\code\models\$(module).Model.cs" />
      <dataStore physicalRootPath="$(configDirectory)\Serialization\$(layer)\$(module)" />
      <templatePredicate rootNamespace="Sample.$(layer).$(module).Models">
        <include name="Templates" path="/sitecore/templates/$(layer)/Sample/$(module)" />
      </templatePredicate>
    </configuration>

    <configuration name="Sample.Feature.Builders" abstract="true">
      <codeGenerator scripts="$(configDirectory)\Foundation\Leprechaun\code\CodeGen\GlassMapper_Builder.csx"
            outputFile="$(configDirectory)\$(layer)\$(module)\tests\builders\$(module).Builders.cs" />
      <dataStore physicalRootPath="$(configDirectory)\Serialization\$(layer)\$(module)" />
      <templatePredicate rootNamespace="Sample.$(layer).$(module).Tests.Builders">
        <include name="Templates" path="/sitecore/templates/$(layer)/Sample/$(module)" />
      </templatePredicate>
    </configuration>

Then we could just have 2 different CodeGen.config files, 1 that lives in the code folder and 1 that lives in tests;

<configuration name="Feature.Sample" extends="Sample.Feature">
</configuration>

<configuration name="Feature.Sample.Builders" extends="Sample.Feature.Builders">
</configuration>

This essentially enabled us, with a single configuration, to generate 2 separate files according to the configuration.

Now we are moving to SCS and using the Leprechaun node as part of the JSON, it seems that we can only have 1 config per module, so I am unable to do the above.

I think the solution is to simply turn the config to accept a JSON array so you can provide multiple configurations, e.g.;

{
  "namespace": "Feature.Sample",
  "references": ["Foundation.*"],
  "items": {
    "includes": [
      {
          "name": "templates",
          "path": "/sitecore/templates/Feature/Sample",
          "allowedPushOperations": "createUpdateAndDelete",
          "scope": "itemAndDescendants"
      }
    ]
  },
  "leprechaun": {
    "configurations": [
        {
            "@extends": "Sample.Feature",
            "@name": "Feature.Sample"
        },
        {
            "@extends": "Sample.Feature.Builders",
            "@name": "Feature.Sample.Builders"
        }
    ]
  }
}

If you have no problem with it, I can take a crack at doing it later this week or this weekend as I have a ready test case for this.

References for builder pattern: https://medium.com/@sawomirkowalski/design-patterns-builder-fluent-interface-and-classic-builder-d16ad3e98f6c https://blog.mzikmund.com/2017/01/c-builder-pattern-with-inheritance/

blipson89 commented 2 years ago

Hi @Ryanh95,

I agree with your solution. If you open a PR for it, I'll gladly merge it. This is a pretty interesting use case I hadn't considered, but totally makes sense.

Thanks, Ben

Ryanh95 commented 2 years ago

Hi Ben,

Can you create me a feature branch with permissions, or give me repository permissions please? I don't seem to have access to push.

Thanks, Ryan

blipson89 commented 2 years ago

Hi Ryan,

At the top-right of the page, right below the nav bar, there's a button called "Fork". It will make a copy of the repo to your Github account. From there, you can create a feature branch in your repo and open a PR into the main Leprechaun repo.

Thanks, Ben