Skip to content

Commit

Permalink
Adds component confix component list (#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
PascalSenn authored Aug 18, 2023
1 parent 0e840a4 commit 743839f
Show file tree
Hide file tree
Showing 12 changed files with 417 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.CommandLine;
using Confix.Commands.Component;
using Confix.Tool.Commands.Project;

namespace Confix.Tool.Commands.Component;
Expand All @@ -10,5 +11,6 @@ public ComponentCommand() : base("component")
Description = "This command is used to manage components.";
AddCommand(new BuildComponentCommand());
AddCommand(new ComponentInitCommand());
AddCommand(new ComponentListCommand());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Confix.Tool.Commands.Component;
using Confix.Tool.Commands.Project;
using Confix.Tool.Commands.Solution;

namespace Confix.Commands.Component;

public sealed class ComponentListCommand : PipelineCommand<ListComponentPipeline>
{
/// <inheritdoc />
public ComponentListCommand() : base("list")
{
Description = "Lists the component of the project";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.Buffers;
using System.CommandLine.Invocation;
using System.Text;
using System.Text.Json;
using Confix.Tool.Commands.Logging;
using Json.More;

namespace Confix.Tool.Commands.Configuration;

public sealed class ComponentListOutputFormatter
: IOutputFormatter<IEnumerable<Confix.Tool.Abstractions.Component>>
{
/// <inheritdoc />
public bool CanHandle(OutputFormat format, IEnumerable<Abstractions.Component> value)
=> format == OutputFormat.Json;

/// <inheritdoc />
public Task<string> FormatAsync(
InvocationContext context,
OutputFormat format,
IEnumerable<Abstractions.Component> value)
{
var options = new JsonWriterOptions
{
Indented = true
};

var buffer = new ArrayBufferWriter<byte>();

using var writer = new Utf8JsonWriter(buffer, options);
writer.WriteStartObject();
writer.WritePropertyName("components");
writer.WriteStartArray();

foreach (var component in value)
{
component.WriteTo(writer);
}

writer.WriteEndArray();
writer.WriteEndObject();
writer.Flush();

return Task.FromResult(Encoding.UTF8.GetString(buffer.WrittenSpan));
}
}

file static class Extensions
{
public static void WriteTo(this Abstractions.Component value, Utf8JsonWriter writer)
{
writer.WriteStartObject();

writer.WriteString("provider", value.Provider);
writer.WriteString("componentName", value.ComponentName);
writer.WriteString("version", value.Version);
writer.WriteBoolean("isEnabled", value.IsEnabled);
writer.WritePropertyName("schema");
value.Schema.ToJsonDocument().WriteTo(writer);
writer.WritePropertyName("mountingPoints");
writer.WriteStartArray();
foreach (var mountingPoint in value.MountingPoints)
{
writer.WriteStringValue(mountingPoint);
}

writer.WriteEndArray();

writer.WriteEndObject();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public static class OutputFormattersConfigurationFilesExtensions
{
public static CommandLineBuilder AddOutputFormatters(this CommandLineBuilder builder)
{
builder.AddOutputFormatter<ComponentListOutputFormatter>();
builder.AddOutputFormatter<ConfigurationFeatureOutputFormatter>();
builder.AddOutputFormatter<ConfigurationFileOutputFormatter>();
return builder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ public static void LogComponentCreated(
console.Information(
$"Component created:{info.Directory?.Name.ToLink(info)} [dim]{info.FullName}[/]");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Confix.Tool.Commands.Logging;
using Confix.Tool.Common.Pipelines;
using Confix.Tool.Entities.Components;
using Confix.Tool.Middlewares;
using Confix.Tool.Middlewares.JsonSchemas;

namespace Confix.Tool.Commands.Component;

public sealed class ListComponentPipeline : Pipeline
{
/// <inheritdoc />
protected override void Configure(IPipelineDescriptor builder)
{
builder
.AddOption(FormatOption.Instance)
.Use<LoadConfigurationMiddleware>()
.UseReadConfigurationFiles()
.UseEnvironment()
.Use<JsonSchemaCollectionMiddleware>()
.Use<ConfigurationAdapterMiddleware>()
.Use<BuildComponentProviderMiddleware>()
.UseHandler(InvokeAsync);
}

private static async Task InvokeAsync(IMiddlewareContext context)
{
context.SetStatus("Listing components...");

var cancellationToken = context.CancellationToken;

var configuration = context.Features.Get<ConfigurationFeature>();

configuration.EnsureProjectScope();

var project = configuration.EnsureProject();
var solution = configuration.EnsureSolution();

var componentProvider =
context.Features.Get<ComponentProviderExecutorFeature>().Executor;

var providerContext =
new ComponentProviderContext(context.Logger, cancellationToken, project, solution);

context.SetStatus("Loading components...");
await componentProvider.ExecuteAsync(providerContext);

context.SetOutput(providerContext.Components);

if (providerContext.Components.Count == 0)
{
context.Logger.Information("No components found");
return;
}

foreach (var file in providerContext.Components)
{
context.Logger.Information(" - " + file.ComponentName);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using Confix.Inputs;
using Confix.Tool.Commands.Temp;

namespace Confix.Commands.Component;

public class ComponentListCommandTests
{
[Fact]
public async Task Should_OutputComponentList_When_Empty()
{
// Arrange
using var cli = new TestConfixCommandline();
cli.Directories.Home.CreateConfixRc(_confixRc);
cli.Directories.Content.CreateConfixProject();
cli.Directories.Content.CreateConfixSolution();
cli.Directories.Content.CreateConsoleApp();

// Act
await cli.RunAsync("component list");

// Assert
SnapshotBuilder
.New()
.AddOutput(cli)
.AddReplacement(cli.Directories.Home.FullName, "HOME")
.AddReplacement(cli.Directories.Content.FullName, "CONTENT")
.MatchSnapshot();
}

[Fact]
public async Task Should_OutputComponentList_When_Provider()
{
// Arrange
using var cli = new TestConfixCommandline();
cli.Directories.Home.CreateConfixRc(_confixRc);
cli.Directories.Content.CreateConfixComponent("test");
cli.Directories.Content.CreateConfixProject();
cli.Directories.Content.CreateConfixSolution();
cli.Directories.Content.CreateConsoleApp();
var componentDirectory = cli.Directories.Content.Append("Components").Append("test");
componentDirectory.CreateFileInPath("schema.graphql", "type Query { str: String }");

// Act
await BuildComponentAsync(cli);
await cli.RunAsync("component list");

// Assert
SnapshotBuilder
.New()
.AddOutput(cli)
.AddReplacement(cli.Directories.Home.FullName, "HOME")
.AddReplacement(cli.Directories.Content.FullName, "CONTENT")
.MatchSnapshot();
}

[Fact]
public async Task Should_OutputComponentList_When_OutputAsJson()
{
// Arrange
using var cli = new TestConfixCommandline();
cli.Directories.Home.CreateConfixRc(_confixRc);
cli.Directories.Content.CreateConfixComponent("test");
cli.Directories.Content.CreateConfixProject();
cli.Directories.Content.CreateConfixSolution();
cli.Directories.Content.CreateConsoleApp();
var componentDirectory = cli.Directories.Content.Append("Components").Append("test");
componentDirectory.CreateFileInPath("schema.graphql", "type Query { str: String }");

// Act
await BuildComponentAsync(cli);
await cli.RunAsync("component list --format json");

// Assert
SnapshotBuilder
.New()
.Append("output", cli.Console.Output)
.AddReplacement(cli.Directories.Home.FullName, "HOME")
.AddReplacement(cli.Directories.Content.FullName, "CONTENT")
.MatchSnapshot();
}

private async Task BuildComponentAsync(TestConfixCommandline cli)
{
var otherCli = new TestConfixCommandline();
otherCli.ExecutionContext = cli.ExecutionContext with
{
CurrentDirectory = cli.ExecutionContext.CurrentDirectory
.Append("Components")
.Append("test")
};
await otherCli.RunAsync("component build");
}

private const string _confixRc = """
{
"isRoot": true,
"component":
{
"inputs": [
{
"type": "graphql"
},
{
"type": "dotnet"
}
]
},
"project": {
"componentProviders": [
{
"name": "dotnet-package",
"type": "dotnet-package"
}
]
}
}
""";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--------------------------------------------------
### CLI Output
--------------------------------------------------
Configuration files of type .confixrc located at <</tmp>>/home/.confixrc
Configuration files of type .confix.solution located at <</tmp>>/content/.confix.solution
Configuration files of type .confix.solution located at <</tmp>>/content/.confix.project
Merged .confix.solution from .confixrc
Merged .confix.project from .confix.solution
Merged .confix.component from .confix.solution
Running in scope Project
Configuration loaded
i No active environment set. Use --environment or set one environment in .confixrc as active
Component provider 'dotnet-package' loaded
Component inputs loaded
Start loading components from project '.'
Found .NET project:'<</tmp>>/content/Confix.csproj' <</tmp>>/content/Confix.csproj
Found assembly: Confix.dll
Scanning assembly: Confix
Found assembly file: <</tmp>>/content/bin/Debug/net8.0/Confix.dll
Scanning assembly: System.Runtime
Assembly file not found for assembly: System.Runtime
Scanning assembly: System.Console
Assembly file not found for assembly: System.Console
Start loading components from project '.'
No components found
Skipping IntelliJ IDEA settings file as there is no .idea folder in the solution root. Expected location: <</tmp>>/content/.idea

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
--------------------------------------------------
### output
--------------------------------------------------
{
"components": [
{
"provider": "dotnet-package",
"componentName": "test",
"version": null,
"isEnabled": true,
"schema": {
"type": "object",
"properties": {
"str": {
"anyOf": [
{
"$ref": "#/$defs/String"
},
{
"type": "null"
}
],
"deprecated": false
}
},
"required": [],
"additionalProperties": false,
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$defs": {
"Query": {
"type": "object",
"properties": {
"str": {
"anyOf": [
{
"$ref": "#/$defs/String"
},
{
"type": "null"
}
],
"deprecated": false
}
},
"required": [],
"additionalProperties": false
},
"String": {
"type": "string",
"hasVariable": true,
"description": "The \u0060String\u0060 scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text."
},
"Boolean": {
"type": "boolean",
"hasVariable": true,
"description": "The \u0060Boolean\u0060 scalar type represents \u0060true\u0060 or \u0060false\u0060."
},
"JSON": {
"type": "string",
"hasVariable": true
}
}
},
"mountingPoints": [
"test"
]
}
]
}
Loading

0 comments on commit 743839f

Please sign in to comment.