Skip to content

Commit

Permalink
Added structured output for creating code templates. #79
Browse files Browse the repository at this point in the history
  • Loading branch information
Jezz Santos committed May 11, 2023
1 parent b3d4b5f commit 556c532
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 48 deletions.
13 changes: 8 additions & 5 deletions docs/authoring.md
Expand Up @@ -473,7 +473,7 @@ automate test codetemplate "<TEMPLATENAME>" --aschildof "{<ANEXPRESSION>}"
automate test codetemplate "ATemplateName" --aschildof "{AnElementName}"
```

### Add code template commands
### Add code template command

!!! abstract "Concept"
A "Code Template Command" is simply a type of automation that executes a "Code Template". This automation must be wired up to a "Code Template", and a "Code Template" must have a "Code Template Command" wired to it, to be applied in any use-case. This kind of command is responsible for deciding how to render the "Code Template" into the target codebase (where in the codebase, and how its named).
Expand Down Expand Up @@ -524,14 +524,17 @@ automate edit add-codetemplate-with-command "<FILEPATH>" --targetpath "<TARGETPA

- The `--name` is an optional friendly name of the code template, which will be used to reference the code template when it is connected to automation later. If no name is specified, an automatic name is assigned to this code template.

- The `--commandname` optionally defines a new name for the command. If no name is specified, an automatic name is assigned to this command.


!!! example
To the pattern:
``` batch
automate edit add-codetemplate-with-command "C:/projects/src/afilename.ext" --name "ATemplateName" --targetpath "~/apath/afilename.ext" --isoneoff
automate edit add-codetemplate-with-command "C:/projects/src/afilename.ext" --name "ATemplateName" --commandname "ACommandName" --targetpath "~/apath/afilename.ext" --isoneoff
```
To an element:
``` batch
automate edit add-codetemplate-with-command "C:/projects/src/afilename.ext" --name "ATemplateName" --targetpath "~/apath/afilename.ext" --isoneoff --aschildof "{AnElementName}"
automate edit add-codetemplate-with-command "C:/projects/src/afilename.ext" --name "ATemplateName" --commandname "ACommandName" --targetpath "~/apath/afilename.ext" --isoneoff --aschildof "{AnElementName}"
```

### Update code template commands
Expand All @@ -549,7 +552,7 @@ automate edit update-codetemplate-command "<COMMANDNAME>" --aschildof "{<ANEXPRE

- The `--isoneoff` optionally defines that the rendered code template will only be generated if it does not already exist on the local machine in the specified location with the specified name. Typically, this means that the code template is only rendered the first time the command is executed.

- The `--name` optionally defines a new name for the command.
- The `--name` optionally defines a new name for the command. If no name is specified, an automatic name is assigned to this command.

!!! example
Of the pattern:
Expand Down Expand Up @@ -609,7 +612,7 @@ automate edit add-cli-command "<APPLICATIONNAME>" --aschildof "{<ANEXPRESSION>}"

- The `--arguments <ARGUMENTS>` optionally defines the arguments to pass to the program. Double-quotes in the arguments must be escaped with double-quotes. The arguments may also contain [Templating Expressions](reference.md#templating-expressions) (relative to the element/collection of the value of `--aschildof`), which will be resolved when the command is applied.

- The `--name` optionally defines a name for the command. If none is given, a default name will be derived for the command.
- The `--name` optionally defines a name for the command. If no name is specified, an automatic name is assigned to this command.

!!! example
To the pattern:
Expand Down
1 change: 1 addition & 0 deletions src/Automate.sln.DotSettings
Expand Up @@ -1193,6 +1193,7 @@ namespace $NAMESPACE$
<s:Boolean x:Key="/Default/UserDictionary/Words/=codetemplate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=codetemplates/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=com/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=commandname/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=defaultvalueis/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=describedas/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=displayedas/@EntryIndexedValue">True</s:Boolean>
Expand Down
7 changes: 4 additions & 3 deletions src/CLI.IntegrationTests/Infrastructure/Api/AuthoringSpec.cs
Expand Up @@ -600,12 +600,12 @@ public void WhenAddCodeTemplateWithCommand_ThenAddsTemplateAndCommand()
this.setup.Should().DisplayNoError();
this.setup.Should()
.DisplayOutput(
OutputMessages.CommandLine_Output_CodeTemplatedAdded.SubstituteTemplate("ATemplateName",
OutputMessages.CommandLine_Output_CodeTemplateAdded.SubstituteTemplate("ATemplateName",
codeTemplate.Id, pattern.Id, codeTemplate.Metadata.OriginalFilePath, codeTemplateLocation));
this.setup.Should()
.DisplayOutput(
OutputMessages.CommandLine_Output_CodeTemplateCommandAdded.SubstituteTemplate(
"ATemplateNameCommand1",
"CodeTemplateCommand1",
this.setup.Pattern.Automation.Single().Id, pattern.Id));
this.setup.Pattern.CodeTemplates.Should().ContainSingle(x => x.Name == "ATemplateName");
}
Expand Down Expand Up @@ -655,7 +655,8 @@ public void WhenViewCodeTemplate_ThenViewsTemplate()
this.setup.Should()
.DisplayOutput(
OutputMessages.CommandLine_Output_CodeTemplateContentViewed.SubstituteTemplate(codeTemplate.Name,
codeTemplate.Id, this.setup.Pattern.Id, codeTemplateLocation, content));
codeTemplate.Id, this.setup.Pattern.Id, codeTemplate.Metadata.OriginalFilePath,
codeTemplate.Metadata.OriginalFileExtension, codeTemplateLocation, content));
}

[Fact]
Expand Down
145 changes: 145 additions & 0 deletions src/CLI.IntegrationTests/Infrastructure/Api/AuthoringStructuredSpec.cs
Expand Up @@ -632,6 +632,151 @@ public void WhenUpdateElement_ThenUpdatesElement()
this.setup.Should().DisplayOutput(structuredOutput);
}

[Fact]
public void WhenViewCodeTemplate_ThenViewsCodeTemplate()
{
this.setup.RunCommand($"{CommandLineApi.CreateCommandName} pattern APattern");
this.setup.RunCommand(
$"{CommandLineApi.EditCommandName} add-codetemplate \"Assets/CodeTemplates/code1.code\" --name ATemplateName");
this.setup.RunCommand(
$"{CommandLineApi.ViewCommandName} codetemplate \"ATemplateName\" --output-structured");

var codeTemplate = this.setup.Pattern.CodeTemplates.Single();
var codeTemplateLocation =
this.setup.PatternStore.GetCodeTemplateLocation(this.setup.Pattern, codeTemplate.Id, "code");

var structuredOutput = new StructuredOutput
{
Info = new List<string>(),
Output = new List<StructuredMessage>
{
new()
{
Message = OutputMessages.CommandLine_Output_CodeTemplateContentViewed,
Values = new Dictionary<string, object>
{
{ "Name", codeTemplate.Name },
{ "Id", codeTemplate.Id },
{ "ParentId", this.setup.Pattern.Id },
{ "OriginalFilePath", codeTemplate.Metadata.OriginalFilePath },
{ "OriginalFileExtension", codeTemplate.Metadata.OriginalFileExtension },
{ "EditorPath", codeTemplateLocation },
{ "Output", "some code" }
}
}
}
}.ToJson();
this.setup.Should().DisplayNoError();
this.setup.Should().DisplayOutput(structuredOutput);
}

[Fact]
public void WhenAddCodeTemplate_ThenAddsCodeTemplate()
{
this.setup.RunCommand($"{CommandLineApi.CreateCommandName} pattern APattern");
this.setup.RunCommand(
$"{CommandLineApi.EditCommandName} add-codetemplate \"Assets/CodeTemplates/code1.code\" --name ATemplateName --output-structured");

var codeTemplate = this.setup.Pattern.CodeTemplates.Single();
var codeTemplateLocation =
this.setup.PatternStore.GetCodeTemplateLocation(this.setup.Pattern, codeTemplate.Id, "code");

var structuredOutput = new StructuredOutput
{
Info = new List<string>
{
$"Information: {OutputMessages.CommandLine_Output_Preamble_CurrentPatternInUse.SubstituteTemplate("APattern", "0.0.0")}"
},
Output = new List<StructuredMessage>
{
new()
{
Message = OutputMessages.CommandLine_Output_CodeTemplateAdded_ForStructured,
Values = new Dictionary<string, object>
{
{ "Name", codeTemplate.Name },
{ "Id", codeTemplate.Id },
{ "ParentId", this.setup.Pattern.Id },
{ "OriginalFilePath", codeTemplate.Metadata.OriginalFilePath },
{ "OriginalFileExtension", codeTemplate.Metadata.OriginalFileExtension },
{ "EditorPath", codeTemplateLocation }
}
}
}
}.ToJson();
this.setup.Should().DisplayNoError();
this.setup.Should().DisplayOutput(structuredOutput);
}

[Fact]
public void WhenAddCodeTemplateWithCommand_ThenAddsCodeTemplateAndCommand()
{
this.setup.RunCommand($"{CommandLineApi.CreateCommandName} pattern APattern");
this.setup.RunCommand(
$"{CommandLineApi.EditCommandName} add-codetemplate-with-command \"Assets/CodeTemplates/code1.code\" --targetpath ~/afilepath --name ATemplateName --output-structured");

var codeTemplate = this.setup.Pattern.CodeTemplates.Single();
var codeTemplateLocation =
this.setup.PatternStore.GetCodeTemplateLocation(this.setup.Pattern, codeTemplate.Id, "code");
var command = this.setup.Pattern.Automation.Single();

var structuredOutput = new StructuredOutput
{
Info = new List<string>
{
$"Information: {OutputMessages.CommandLine_Output_Preamble_CurrentPatternInUse.SubstituteTemplate("APattern", "0.0.0")}"
},
Output = new List<StructuredMessage>
{
new()
{
Message = OutputMessages
.CommandLine_Output_CodeTemplateWithCommandAdded_CodeTemplate_ForStructured,
Values = new Dictionary<string, object>
{
{
"CodeTemplate", new Dictionary<string, object>
{
{ "Name", codeTemplate.Name },
{ "Id", codeTemplate.Id },
{ "ParentId", this.setup.Pattern.Id },
{ "OriginalFilePath", codeTemplate.Metadata.OriginalFilePath },
{ "OriginalFileExtension", codeTemplate.Metadata.OriginalFileExtension },
{ "EditorPath", codeTemplateLocation }
}
}
}
},
new()
{
Message = OutputMessages.CommandLine_Output_CodeTemplateWithCommandAdded_Command_ForStructured,
Values = new Dictionary<string, object>
{
{
"Command", new Dictionary<string, object>
{
{ "Name", command.Name },
{ "Id", command.Id },
{ "ParentId", this.setup.Pattern.Id },
{ "Type", command.Type.ToString() },
{
"Metadata", new Dictionary<string, object>
{
{ "CodeTemplateId", codeTemplate.Id },
{ "IsOneOff", false },
{ "FilePath", "~/afilepath" }
}
}
}
}
}
}
}
}.ToJson();
this.setup.Should().DisplayNoError();
this.setup.Should().DisplayOutput(structuredOutput);
}

public void Dispose()
{
this.setup.Reset();
Expand Down
73 changes: 56 additions & 17 deletions src/CLI/Infrastructure/Api/AuthoringApiHandlers.cs
Expand Up @@ -281,31 +281,69 @@ internal static void DeleteCollection(string name, string asChildOf)
element.Id, parent.Id);
}

internal static void AddCodeTemplate(string filepath, string name, string asChildOf)
internal static void AddCodeTemplate(string filepath, string name, string asChildOf, bool outputStructured)
{
var currentDirectory = Metadata.CurrentExecutionPath;
var (parent, template) = authoring.AddCodeTemplate(currentDirectory, filepath, name, asChildOf);
Output(OutputMessages.CommandLine_Output_CodeTemplatedAdded, template.Template.Name,
template.Template.Id,
parent.Id, template.Template.Metadata.OriginalFilePath, template.Location);
if (outputStructured)
{
Output(OutputMessages.CommandLine_Output_CodeTemplateAdded_ForStructured, template.Template.Name,
template.Template.Id, parent.Id, template.Template.Metadata.OriginalFilePath,
template.Template.Metadata.OriginalFileExtension,
template.Location);
}
else
{
Output(OutputMessages.CommandLine_Output_CodeTemplateAdded, template.Template.Name,
template.Template.Id, parent.Id, template.Template.Metadata.OriginalFilePath,
template.Location);
}
}

internal static void AddCodeTemplateWithCommand(string filepath, string name, bool isOneOff,
string targetPath, string asChildOf)
internal static void AddCodeTemplateWithCommand(string filepath, string name, string commandName,
bool isOneOff,
string targetPath, string asChildOf, bool outputStructured)
{
var currentDirectory = Metadata.CurrentExecutionPath;
var (parent, template, command) = authoring.AddCodeTemplateWithCommand(currentDirectory, filepath,
name, isOneOff, targetPath, asChildOf);
Output(OutputMessages.CommandLine_Output_CodeTemplatedAdded, template.Template.Name,
template.Template.Id, parent.Id, template.Template.Metadata.OriginalFilePath,
template.Location);
Output(OutputMessages.CommandLine_Output_CodeTemplateCommandAdded,
command.Name, command.Id, parent.Id);
name, commandName, isOneOff, targetPath, asChildOf);
if (outputStructured)
{
Output(OutputMessages.CommandLine_Output_CodeTemplateWithCommandAdded_CodeTemplate_ForStructured,
JsonNode.Parse(new
{
template.Template.Name,
template.Template.Id,
ParentId = parent.Id,
template.Template.Metadata.OriginalFilePath,
template.Template.Metadata.OriginalFileExtension,
EditorPath = template.Location
}.ToJson()));
Output(OutputMessages.CommandLine_Output_CodeTemplateWithCommandAdded_Command_ForStructured,
JsonNode.Parse(new
{
command.Name,
command.Id,
ParentId = parent.Id,
Type = command.Type.ToString(),
command.Metadata
}.ToJson()));
}
else
{
Output(OutputMessages.CommandLine_Output_CodeTemplateAdded, template.Template.Name,
template.Template.Id, parent.Id, template.Template.Metadata.OriginalFilePath,
template.Location);
Output(OutputMessages.CommandLine_Output_CodeTemplateCommandAdded,
command.Name, command.Id, parent.Id);
}
}

internal static void EditCodeTemplate(string templateName, string with, string args, string asChildOf)
internal static void EditCodeTemplateContent(string templateName, string with, string args,
string asChildOf)
{
var (parent, template, location) = authoring.EditCodeTemplate(templateName, with, args, asChildOf);
var (parent, template, location) =
authoring.EditCodeTemplateContent(templateName, with, args, asChildOf);
Output(OutputMessages.CommandLine_Output_CodeTemplateContentEdited, template.Name, template.Id,
parent.Id, with, location);
}
Expand Down Expand Up @@ -340,11 +378,12 @@ internal static void DeleteCodeTemplate(string templateName, string asChildOf)
test.Template.Id, test.Output);
}

internal static void ViewCodeTemplate(string templateName, string asChildOf, bool outputStructured)
internal static void ViewCodeTemplateContent(string templateName, string asChildOf)
{
var (parent, template, location, content) = authoring.ViewCodeTemplate(templateName, asChildOf);
var (parent, template, location, content) = authoring.ViewCodeTemplateContent(templateName, asChildOf);
Output(OutputMessages.CommandLine_Output_CodeTemplateContentViewed, template.Name, template.Id,
parent.Id, location, content);
parent.Id, template.Metadata.OriginalFilePath, template.Metadata.OriginalFileExtension, location,
content);
}

internal static void AddCodeTemplateCommand(string codeTemplateName, string name, bool isOneOff,
Expand Down

0 comments on commit 556c532

Please sign in to comment.