diff --git a/.gitignore b/.gitignore index 499cb3d..1419c10 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,6 @@ mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ diff --git a/Enterspeed.Cli.sln b/Enterspeed.Cli.sln index b9217aa..0503ae4 100644 --- a/Enterspeed.Cli.sln +++ b/Enterspeed.Cli.sln @@ -20,6 +20,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "releaseNotes", "releaseNote releaseNotes\1.2.0.md = releaseNotes\1.2.0.md releaseNotes\1.3.0.md = releaseNotes\1.3.0.md releaseNotes\1.4.0.md = releaseNotes\1.4.0.md + releaseNotes\1.5.0.md = releaseNotes\1.5.0.md EndProjectSection EndProject Global diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7415afc..5e946ef 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,7 +2,7 @@ variables: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 vmPool: 'windows-latest' majorVersion: 1 - minorVersion: 4 + minorVersion: 5 patchVersion: 0 version: $[format('{0}.{1}.{2}', variables.majorVersion, variables.minorVersion, variables.patchVersion)] ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}: diff --git a/releaseNotes/1.5.0.md b/releaseNotes/1.5.0.md new file mode 100644 index 0000000..efd22b3 --- /dev/null +++ b/releaseNotes/1.5.0.md @@ -0,0 +1,2 @@ +### Added +- Added support for partial schemas (require new partial schemas enable on tenant) diff --git a/src/Enterspeed.Cli/Api/MappingSchema/CreateMappingSchemaRequest.cs b/src/Enterspeed.Cli/Api/MappingSchema/CreateMappingSchemaRequest.cs index ccf6cfb..02862b8 100644 --- a/src/Enterspeed.Cli/Api/MappingSchema/CreateMappingSchemaRequest.cs +++ b/src/Enterspeed.Cli/Api/MappingSchema/CreateMappingSchemaRequest.cs @@ -8,6 +8,7 @@ public class CreateMappingSchemaRequest : IRequest { public string Name { get; set; } public string ViewHandle { get; set; } + public string Type { get; set; } } public class CreateMappingSchemaResponse diff --git a/src/Enterspeed.Cli/Api/MappingSchema/DeployMappingSchema.cs b/src/Enterspeed.Cli/Api/MappingSchema/DeployMappingSchema.cs deleted file mode 100644 index c86bb0a..0000000 --- a/src/Enterspeed.Cli/Api/MappingSchema/DeployMappingSchema.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Enterspeed.Cli.Domain.Models; -using Enterspeed.Cli.Services.EnterspeedClient; -using MediatR; -using RestSharp; -using System.Text.Json; - -namespace Enterspeed.Cli.Api.MappingSchema -{ - public class DeployMappingSchemaRequest : IRequest - { - public string SchemaId { get; set; } - - public string Comment { get; set; } - - public List Deployments { get; set; } - - public class EnvironmentSchemaDeployment - { - public string EnvironmentId { get; set; } - public int? Version { get; set; } - } - } - - public class DeployMappingSchemaResponse - { - public bool Success { get; set; } - public ApiErrorResponse Error { get; set; } - } - - public class DeployMappingSchemaRequestHandler : IRequestHandler - { - private readonly IEnterspeedClient _enterspeedClient; - - public DeployMappingSchemaRequestHandler(IEnterspeedClient enterspeedClient) - { - _enterspeedClient = enterspeedClient; - } - - public async Task Handle(DeployMappingSchemaRequest deployMappingSchemaRequest, CancellationToken cancellationToken) - { - var request = new RestRequest($"tenant/mapping-schemas/deploy", Method.Post).AddJsonBody(deployMappingSchemaRequest); - var response = await _enterspeedClient.ExecuteAsync(request, cancellationToken); - - var validateResponse = new DeployMappingSchemaResponse { Success = response.IsSuccessful }; - // TODO: Extract to common enterspeed client - if (!response.IsSuccessful && !string.IsNullOrEmpty(response.Content)) - { - validateResponse.Error = JsonSerializer.Deserialize(response.Content); - } - - return validateResponse; - } - } -} \ No newline at end of file diff --git a/src/Enterspeed.Cli/Api/MappingSchema/GetMappingSchemaRequest.cs b/src/Enterspeed.Cli/Api/MappingSchema/GetMappingSchemaRequest.cs index e9bac80..f700a03 100644 --- a/src/Enterspeed.Cli/Api/MappingSchema/GetMappingSchemaRequest.cs +++ b/src/Enterspeed.Cli/Api/MappingSchema/GetMappingSchemaRequest.cs @@ -1,4 +1,5 @@ using Enterspeed.Cli.Api.MappingSchema.Models; +using Enterspeed.Cli.Domain.Models; using Enterspeed.Cli.Services.EnterspeedClient; using MediatR; using RestSharp; @@ -16,6 +17,7 @@ public class GetMappingSchemaResponse public string Name { get; set; } public string ViewHandle { get; set; } public int LatestVersion { get; set; } + public SchemaType Type { get; set; } public MappingSchemaVersion Version { get; set; } public List Deployments { get; set; } } diff --git a/src/Enterspeed.Cli/Api/MappingSchema/ValidateMappingSchema.cs b/src/Enterspeed.Cli/Api/MappingSchema/ValidateMappingSchema.cs deleted file mode 100644 index 71f03af..0000000 --- a/src/Enterspeed.Cli/Api/MappingSchema/ValidateMappingSchema.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Text.Json; -using Enterspeed.Cli.Domain.Models; -using Enterspeed.Cli.Services.EnterspeedClient; -using MediatR; -using RestSharp; - -namespace Enterspeed.Cli.Api.MappingSchema; - -public class ValidateMappingSchemaRequest : IRequest -{ - public string MappingSchemaId { get; set; } - public int Version { get; set; } -} - -public class ValidateMappingSchemaResponse -{ - public bool Success { get; set; } - public ApiErrorResponse Error { get; set; } -} - - -public class ValidateMappingSchemaRequestHandler : IRequestHandler -{ - private readonly IEnterspeedClient _enterspeedClient; - - public ValidateMappingSchemaRequestHandler(IEnterspeedClient enterspeedClient) - { - _enterspeedClient = enterspeedClient; - } - - public async Task Handle(ValidateMappingSchemaRequest validateMappingSchemaRequest, CancellationToken cancellationToken) - { - var request = new RestRequest($"tenant/mapping-schemas/{validateMappingSchemaRequest.MappingSchemaId}/version/{validateMappingSchemaRequest.Version}/_validate", Method.Put); - var response = await _enterspeedClient.ExecuteAsync(request, cancellationToken); - - var validateResponse = new ValidateMappingSchemaResponse {Success = response.IsSuccessful}; - - // TODO: Extract to common enterspeed client - if (!response.IsSuccessful && !string.IsNullOrEmpty(response.Content)) - { - validateResponse.Error = JsonSerializer.Deserialize(response.Content); - } - - return validateResponse; - } -} \ No newline at end of file diff --git a/src/Enterspeed.Cli/Api/Release/CreateRelease.cs b/src/Enterspeed.Cli/Api/Release/CreateRelease.cs new file mode 100644 index 0000000..737eb38 --- /dev/null +++ b/src/Enterspeed.Cli/Api/Release/CreateRelease.cs @@ -0,0 +1,61 @@ +using Enterspeed.Cli.Domain.Models; +using Enterspeed.Cli.Services.EnterspeedClient; +using MediatR; +using RestSharp; +using System.Text.Json; + +namespace Enterspeed.Cli.Api.Release; + +public class CreateReleaseRequest : IRequest +{ + public string EnvironmentId { get; set; } + public SchemaVersionId[] Schemas { get; set; } +} + +public class SchemaVersionId +{ + public string SchemaId { get; set; } + public int? Version { get; set; } +} + +public class CreateReleaseResponse +{ + public bool Success { get; set; } + public ApiErrorBaseResponse Error { get; set; } +} + +public class CreateReleaseRequestHandler : IRequestHandler +{ + private readonly IEnterspeedClient _enterspeedClient; + + public CreateReleaseRequestHandler(IEnterspeedClient enterspeedClient) + { + _enterspeedClient = enterspeedClient; + } + + public async Task Handle(CreateReleaseRequest createRequest, CancellationToken cancellationToken) + { + var request = new RestRequest("tenant/releases", Method.Post) + .AddJsonBody(createRequest); + + var response = await _enterspeedClient.ExecuteAsync(request, cancellationToken); + + var createReleaseResponse = new CreateReleaseResponse { Success = response.IsSuccessful }; + + if (!response.IsSuccessful && !string.IsNullOrEmpty(response.Content)) + { + var apiErrorBaseResponse = JsonSerializer.Deserialize(response.Content); + + if (apiErrorBaseResponse.Code == ErrorCode.FailedToCreateRelease) + { + createReleaseResponse.Error = JsonSerializer.Deserialize(response.Content); + } + else + { + createReleaseResponse.Error = JsonSerializer.Deserialize(response.Content); + } + } + + return createReleaseResponse; + } +} \ No newline at end of file diff --git a/src/Enterspeed.Cli/Commands/Deploy/DeployCommand.cs b/src/Enterspeed.Cli/Commands/Deploy/DeployCommand.cs index e00a8ff..f5e36d7 100644 --- a/src/Enterspeed.Cli/Commands/Deploy/DeployCommand.cs +++ b/src/Enterspeed.Cli/Commands/Deploy/DeployCommand.cs @@ -7,181 +7,164 @@ using Enterspeed.Cli.Api.MappingSchema; using Enterspeed.Cli.Domain.Models; using Enterspeed.Cli.Services.FileService.Models; +using Enterspeed.Cli.Api.Release; +using System.Text.Json; -namespace Enterspeed.Cli.Commands.Deploy +namespace Enterspeed.Cli.Commands.Deploy; + +public class DeployCommand : Command { - public class DeployCommand : Command + public DeployCommand() : base(name: "deploy", "Deploy schemas using deploymentplan") + { + AddOption(new Option(new[] { "--environment", "-e" }, "Target environment for deploy") { IsRequired = true }); + AddOption(new Option(new[] { "--deploymentplan", "-dp" }, "Deploymentplan to use")); + } + + public new class Handler : BaseCommandHandler, ICommandHandler { - public DeployCommand() : base(name: "deploy", "Deploy schemas using deploymentplan") + private readonly IMediator _mediator; + private readonly IDeploymentPlanFileService _deploymentPlanFileService; + private readonly ILogger _logger; + + public Handler(IMediator mediator, + ILogger logger, + IDeploymentPlanFileService deploymentPlanFileService) { - AddOption(new Option(new[] { "--environment", "-e" }, "Target environment for deploy") { IsRequired = true }); - AddOption(new Option(new[] { "--deploymentplan", "-dp" }, "Deploymentplan to use")); + _mediator = mediator; + _logger = logger; + _deploymentPlanFileService = deploymentPlanFileService; } - public new class Handler : BaseCommandHandler, ICommandHandler + public string Environment { get; set; } + + public string DeploymentPlan { get; set; } = DedploymentPlanFileService.DefaultDeploymentPlanFileName; + + public async Task InvokeAsync(InvocationContext context) { - private readonly IMediator _mediator; - private readonly IDeploymentPlanFileService _deploymentPlanFileService; - private readonly ILogger _logger; + _logger.LogInformation($"Deploy {DeploymentPlan} to {Environment}"); - public Handler(IMediator mediator, - ILogger logger, - IDeploymentPlanFileService deploymentPlanFileService) + // Read deployment plan file + var plan = _deploymentPlanFileService.GetDeploymentPlan(DeploymentPlan); + if (plan == null) { - _mediator = mediator; - _logger = logger; - _deploymentPlanFileService = deploymentPlanFileService; + _logger.LogError($"Deployment plan {DeploymentPlan} not found!"); + return 1; } - public string Environment { get; set; } + if (!plan.Schemas.Any()) + { + _logger.LogError($"Deployment plan contains no schemas!"); + return 1; + } - public string DeploymentPlan { get; set; } = DedploymentPlanFileService.DefaultDeploymentPlanFileName; + // Resolve environment alias + var targetEnvironment = await GetTargetEnvironmentId(Environment); + if (targetEnvironment == null) + { + _logger.LogError($"Environment {Environment} not found!"); + return 1; + } - public async Task InvokeAsync(InvocationContext context) + // Fetch schemas to deploy + var schemasToDeploy = await FetchSchemas(plan.Schemas); + if (schemasToDeploy == null) { - _logger.LogInformation($"Deploy {DeploymentPlan} to {Environment}"); + return 1; + } - // Read deployment plan file - var plan = _deploymentPlanFileService.GetDeploymentPlan(DeploymentPlan); - if (plan == null) - { - _logger.LogError($"Deployment plan {DeploymentPlan} not found!"); - return 1; - } + // Check if schemas are locked + if (!EnsureSchemasLocked(schemasToDeploy)) + { + return 1; + } - if (!plan.Schemas.Any()) + // Execute deployment + var createReleaseRequest = new CreateReleaseRequest + { + EnvironmentId = targetEnvironment.IdValue, + Schemas = schemasToDeploy.Select(x => new SchemaVersionId { - _logger.LogError($"Deployment plan contains no schemas!"); - return 1; - } + SchemaId = x.Version.Id.IdValue, + Version = x.Version.Id.Version + }).ToArray() + }; - // Resolve environment alias - var targetEnvironment = await GetTargetEnvironmentId(Environment); - if (targetEnvironment == null) - { - _logger.LogError($"Environment {Environment} not found!"); - return 1; - } + var createReleaseResponse = await _mediator.Send(createReleaseRequest); - // Fetch schemas to deploy - var schemasToDeploy = await FetchSchemas(plan.Schemas); - if (schemasToDeploy == null) - { - return 1; - } + if (!createReleaseResponse.Success) + { + LogError(createReleaseResponse.Error); + return 1; + } - // Check if schemas are locked - if (!EnsureSchemasLocked(schemasToDeploy)) - { - return 1; - } + return 0; + } + + private async Task GetTargetEnvironmentId(string environmentName) + { + var environments = await _mediator.Send(new GetEnvironmentsRequest()); + var targetEnvironment = environments.FirstOrDefault(env => env.Name == environmentName); + return targetEnvironment?.Id; + } + + private async Task> FetchSchemas(List planSchemas) + { + var schemas = new List(); - // Validate all schemas - if (!await ValidateSchemas(schemasToDeploy)) + // Resolve schema aliases + var schemaQueryResponse = await _mediator.Send(new QueryMappingSchemasRequest()); + + foreach (var planSchema in planSchemas) + { + var mappingSchemaId = schemaQueryResponse.FirstOrDefault(x => x.ViewHandle == planSchema.Schema)?.Id; + if (mappingSchemaId == null) { - return 1; + _logger.LogError($"Schema with alias {planSchema.Schema} not found"); + return null; } - // Execute deployment - foreach (var schema in schemasToDeploy) - { - var deployRequest = new DeployMappingSchemaRequest - { - SchemaId = schema.Version.Id.IdValue, - Deployments = new List - { - new() - { - EnvironmentId = targetEnvironment.IdValue, - Version = schema.Version.Id.Version - } - } - }; - - var deployResponse = await _mediator.Send(deployRequest); - - if (!deployResponse.Success) + var schema = await _mediator.Send( + new GetMappingSchemaRequest { - _logger.LogError($"Schema {schema.ViewHandle} failed deployment ({deployResponse.Error?.Code})"); - // TODO: Log better error messages - return 1; + MappingSchemaId = mappingSchemaId.MappingSchemaGuid, + Version = planSchema.Version } - } - - return 0; + ); + schemas.Add(schema); } - private async Task GetTargetEnvironmentId(string environmentName) - { - var environments = await _mediator.Send(new GetEnvironmentsRequest()); - var targetEnvironment = environments.FirstOrDefault(env => env.Name == environmentName); - return targetEnvironment?.Id; - } + return schemas; + } - private async Task> FetchSchemas(List planSchemas) + private bool EnsureSchemasLocked(IEnumerable schemasToDeploy) + { + foreach (var schema in schemasToDeploy) { - var schemas = new List(); - - // Resolve schema aliases - var schemaQueryResponse = await _mediator.Send(new QueryMappingSchemasRequest()); - - foreach (var planSchema in planSchemas) + if (schema.Version.IsEditAble) { - var mappingSchemaId = schemaQueryResponse.FirstOrDefault(x => x.ViewHandle == planSchema.Schema)?.Id; - if (mappingSchemaId == null) - { - _logger.LogError($"Schema with alias {planSchema.Schema} not found"); - return null; - } - - var schema = await _mediator.Send( - new GetMappingSchemaRequest - { - MappingSchemaId = mappingSchemaId.MappingSchemaGuid, - Version = planSchema.Version - } - ); - schemas.Add(schema); + _logger.LogError($"Schema {schema.ViewHandle} is not locked"); + return false; } - - return schemas; } - private bool EnsureSchemasLocked(IEnumerable schemasToDeploy) + return true; + } + + private void LogError(ApiErrorBaseResponse apiErrorBaseResponse) + { + if (apiErrorBaseResponse is ApiGroupedErrorResponse apiGroupedErrorResponse) { - foreach (var schema in schemasToDeploy) + foreach (var groupedError in apiGroupedErrorResponse.Errors) { - if (schema.Version.IsEditAble) - { - _logger.LogError($"Schema {schema.ViewHandle} is not locked"); - return false; - } + var error = JsonSerializer.Serialize(groupedError.Errors); + _logger.LogError("Something went wrong when deploying schema with id '" + groupedError.Name + "': " + error); } - - return true; } - - private async Task ValidateSchemas(IEnumerable schemasToDeploy) + else { - foreach (var schema in schemasToDeploy) - { - var validateResponse = await _mediator.Send(new ValidateMappingSchemaRequest - { - MappingSchemaId = schema.Version.Id.MappingSchemaGuid, - Version = schema.Version.Id.Version - }); - - if (!validateResponse.Success) - { - _logger.LogError($"Schema {schema.ViewHandle} failed validation ({validateResponse.Error?.Code})"); - // TODO: Log better error messages - return false; - } - } - - return true; + var error = JsonSerializer.Serialize((ApiErrorResponse)apiErrorBaseResponse); + _logger.LogError("Deployment of schemas failed: " + error); } - } } -} +} \ No newline at end of file diff --git a/src/Enterspeed.Cli/Commands/Schema/CloneSchemaCommand.cs b/src/Enterspeed.Cli/Commands/Schema/CloneSchemaCommand.cs index 44192e0..ea747df 100644 --- a/src/Enterspeed.Cli/Commands/Schema/CloneSchemaCommand.cs +++ b/src/Enterspeed.Cli/Commands/Schema/CloneSchemaCommand.cs @@ -5,54 +5,53 @@ using System.CommandLine; using System.CommandLine.Invocation; -namespace Enterspeed.Cli.Commands.Schema +namespace Enterspeed.Cli.Commands.Schema; + +internal class CloneSchemaCommand : Command { - internal class CloneSchemaCommand : Command + public CloneSchemaCommand() : base("clone", "Creates all schemas on tenant as json files on disk, in latest versions under /schemas") + { + } + + public new class Handler : BaseCommandHandler, ICommandHandler { - public CloneSchemaCommand() : base("clone", "Creates all schemas on tenant as json files on disk, in latest versions under /schemas") + private readonly IMediator _mediator; + private readonly IOutputService _outputService; + private readonly ISchemaFileService _schemaFileService; + + public Handler(IMediator mediator, IOutputService outputService, ISchemaFileService schemaFileService) { + _mediator = mediator; + _outputService = outputService; + _schemaFileService = schemaFileService; } - public new class Handler : BaseCommandHandler, ICommandHandler + public async Task InvokeAsync(InvocationContext context) { - private readonly IMediator _mediator; - private readonly IOutputService _outputService; - private readonly ISchemaFileService _schemaFileService; - - public Handler(IMediator mediator, IOutputService outputService, ISchemaFileService schemaFileService) - { - _mediator = mediator; - _outputService = outputService; - _schemaFileService = schemaFileService; - } + var allSchemas = await _mediator.Send(new QueryMappingSchemasRequest()); + var schemaResponses = new List(); - public async Task InvokeAsync(InvocationContext context) + foreach (var schema in allSchemas) { - var allSchemas = await _mediator.Send(new QueryMappingSchemasRequest()); - var schemaResponses = new List(); - - foreach (var schema in allSchemas) + var schemaResponse = await _mediator.Send(new GetMappingSchemaRequest { - var schemaResponse = await _mediator.Send(new GetMappingSchemaRequest() - { - MappingSchemaId = schema.Id.MappingSchemaGuid - }); - - if (schemaResponse != null) - { - schemaResponses.Add(schemaResponse); - } - } + MappingSchemaId = schema.Id.MappingSchemaGuid + }); - foreach (var schema in schemaResponses) + if (schemaResponse != null) { - _schemaFileService.CreateSchema(schema.ViewHandle, schema.Version.Data); + schemaResponses.Add(schemaResponse); } + } - _outputService.Write("Successfully cloned all schemas"); - - return 0; + foreach (var schema in schemaResponses) + { + _schemaFileService.CreateSchema(schema.ViewHandle, schema.Type, schema.Version.Data); } + + _outputService.Write("Successfully cloned all schemas"); + + return 0; } } -} +} \ No newline at end of file diff --git a/src/Enterspeed.Cli/Commands/Schema/CreateSchemaCommand.cs b/src/Enterspeed.Cli/Commands/Schema/CreateSchemaCommand.cs index 3f678ab..097e16d 100644 --- a/src/Enterspeed.Cli/Commands/Schema/CreateSchemaCommand.cs +++ b/src/Enterspeed.Cli/Commands/Schema/CreateSchemaCommand.cs @@ -1,7 +1,10 @@ using System.CommandLine; using System.CommandLine.Invocation; +using System.Text.Json; using Enterspeed.Cli.Api.MappingSchema; +using Enterspeed.Cli.Domain.Models; using Enterspeed.Cli.Exceptions; +using Enterspeed.Cli.Extensions; using Enterspeed.Cli.Services.ConsoleOutput; using Enterspeed.Cli.Services.FileService; using MediatR; @@ -13,7 +16,8 @@ internal class CreateSchemaCommand : Command { public CreateSchemaCommand() : base(name: "create", "Creates schema") { - AddArgument(new Argument("alias", "Alias of the schema") { }); + AddArgument(new Argument("alias", "Alias of the schema")); + AddOption(new Option(new[] { "--type", "-t" }, "Type of the schema (full or partial). Default value is full")); AddOption(new Option(new[] { "--name", "-n" }, "Name of the schema")); } @@ -37,6 +41,7 @@ public Handler(IMediator mediator, public string Alias { get; set; } public string Name { get; set; } + public string Type { get; set; } public async Task InvokeAsync(InvocationContext context) { @@ -45,15 +50,22 @@ public async Task InvokeAsync(InvocationContext context) throw new ConsoleArgumentException("Please specify an alias for your schema"); } - var createSchemaResponse = await _mediator.Send(new CreateMappingSchemaRequest() + var schemaType = GetSchemaType(); + if (!schemaType.HasValue) + { + throw new ConsoleArgumentException("Please specify a valid value for type"); + } + + var createSchemaResponse = await _mediator.Send(new CreateMappingSchemaRequest { Name = Name ?? Alias, - ViewHandle = Alias + ViewHandle = Alias, + Type = schemaType.Value.ToApiString() }); if (createSchemaResponse?.IdValue != null && !string.IsNullOrEmpty(createSchemaResponse.MappingSchemaGuid)) { - _schemaFileService.CreateSchema(Alias); + _schemaFileService.CreateSchema(Alias, schemaType.Value); } else { @@ -61,10 +73,45 @@ public async Task InvokeAsync(InvocationContext context) return 1; } + if (schemaType == SchemaType.Partial) + { + await UpdateSchemaToPartialTemplate(createSchemaResponse.MappingSchemaGuid); + } + _outputService.Write("Successfully created new schema : " + Alias); return 0; } + + // Maybe this should be handled in the management API see shortcut story: 3226 + private async Task UpdateSchemaToPartialTemplate(string mappingSchemaGuid) + { + var schema = _schemaFileService.GetSchema(Alias)?.SchemaBaseProperties; + + var updateSchemaResponse = await _mediator.Send(new UpdateMappingSchemaRequest + { + Format = "json", + MappingSchemaId = mappingSchemaGuid, + Version = 1, + Schema = JsonSerializer.SerializeToDocument(schema, SchemaFileService.SerializerOptions) + }); + } + + // We are using the terms "full" as public facing term but "normal" inside the code base, so we have to do some manual mapping + private SchemaType? GetSchemaType() + { + if (string.IsNullOrWhiteSpace(Type) || Type.Equals("full", StringComparison.InvariantCultureIgnoreCase)) + { + return SchemaType.Normal; + } + + if (Enum.TryParse(Type, true, out SchemaType schemaType)) + { + return schemaType; + } + + return null; + } } } } \ No newline at end of file diff --git a/src/Enterspeed.Cli/Commands/Schema/DeploySchemaCommand.cs b/src/Enterspeed.Cli/Commands/Schema/DeploySchemaCommand.cs index c19e1cf..adc96bf 100644 --- a/src/Enterspeed.Cli/Commands/Schema/DeploySchemaCommand.cs +++ b/src/Enterspeed.Cli/Commands/Schema/DeploySchemaCommand.cs @@ -3,155 +3,152 @@ using System.Text.Json; using Enterspeed.Cli.Api.Environment; using Enterspeed.Cli.Api.MappingSchema; +using Enterspeed.Cli.Api.Release; using Enterspeed.Cli.Domain.Models; using Enterspeed.Cli.Services.ConsoleOutput; using Enterspeed.Cli.Services.FileService; using MediatR; using Microsoft.Extensions.Logging; -namespace Enterspeed.Cli.Commands.Schema +namespace Enterspeed.Cli.Commands.Schema; + +internal class DeploySchemaCommand : Command { - internal class DeploySchemaCommand : Command + public DeploySchemaCommand() : base("deploy", "Adds schema to deployment plan") { - public DeploySchemaCommand() : base("deploy", "Adds schema to deployment plan") + AddArgument(new Argument("alias", "Alias of the schema")); + AddOption(new Option(new[] { "--environment", "-e" }, "Environment name") { - AddArgument(new Argument("alias", "Alias of the schema") { }); - AddOption(new Option(new[] { "--environment", "-e" }, "Environment name") - { - IsRequired = true - }); + IsRequired = true + }); + } + + public new class Handler : BaseCommandHandler, ICommandHandler + { + private readonly IMediator _mediator; + private readonly IOutputService _outputService; + private readonly ISchemaFileService _schemaFileService; + private readonly ILogger _logger; + private readonly IDeploymentPlanFileService _deploymentPlanFileService; + + public Handler( + IMediator mediator, + IOutputService outputService, + ISchemaFileService schemaFileService, + ILogger logger, + IDeploymentPlanFileService deploymentPlanFileService) + { + _outputService = outputService; + _mediator = mediator; + _schemaFileService = schemaFileService; + _logger = logger; + _deploymentPlanFileService = deploymentPlanFileService; } - public new class Handler : BaseCommandHandler, ICommandHandler + public string Alias { get; set; } + public string Environment { get; set; } + + public async Task InvokeAsync(InvocationContext context) { - private readonly IMediator _mediator; - private readonly IOutputService _outputService; - private readonly ISchemaFileService _schemaFileService; - private readonly ILogger _logger; - private readonly IDeploymentPlanFileService _deploymentPlanFileService; - - public Handler( - IMediator mediator, - IOutputService outputService, - ISchemaFileService schemaFileService, - ILogger logger, - IDeploymentPlanFileService deploymentPlanFileService) + // Get mapping schema guid + var mappingSchemaId = await GetMappingSchemaGuid(); + if (mappingSchemaId == null) { - _outputService = outputService; - _mediator = mediator; - _schemaFileService = schemaFileService; - _logger = logger; - _deploymentPlanFileService = deploymentPlanFileService; + _logger.LogError("Mapping schema id not found!"); + return 1; } - public string Alias { get; set; } - public string Environment { get; set; } - - public async Task InvokeAsync(InvocationContext context) + // Get version from existing schema + var existingSchema = await GetExistingSchema(mappingSchemaId.MappingSchemaGuid); + if (existingSchema == null) { - // Get mapping schema guid - var mappingSchemaId = await GetMappingSchemaGuid(); - if (mappingSchemaId == null) - { - _logger.LogError("Mapping schema id not found!"); - return 1; - } - - // Get version from existing schema - var existingSchema = await GetExistingSchema(mappingSchemaId.MappingSchemaGuid); - if (existingSchema == null) - { - _logger.LogError("Schema not found!"); - return 1; - } - - // Validate that schema on disk matches schema saved in Enterspeed. - var valid = _schemaFileService.SchemaValid(existingSchema.Version.Data, Alias); - if (!valid) - { - _logger.LogError("Schema on disk does not match schema in Enterspeed. Save your schema before deploying it."); - return 1; - } + _logger.LogError("Schema not found!"); + return 1; + } - // Ensure that content of schema is valid - var validationResponse = await ValidateMappingSchema(existingSchema, mappingSchemaId.MappingSchemaGuid); - if (!validationResponse.Success) - { - var error = JsonSerializer.Serialize(validationResponse.Error); - _logger.LogError("Schema not valid: " + error); - return 1; - } + // Validate that schema on disk matches schema saved in Enterspeed. + var valid = _schemaFileService.SchemaValid(existingSchema.Version.Data, Alias); + if (!valid) + { + _logger.LogError("Schema on disk does not match schema in Enterspeed. Save your schema before deploying it."); + return 1; + } - // Deploy schema - var environmentToDeployTo = await GetEnvironmentToDeployTo(); - if (environmentToDeployTo == null) - { - _logger.LogError("Environment to deploy to was not found"); - return 1; - } + // Deploy schema + var environmentToDeployTo = await GetEnvironmentToDeployTo(); + if (environmentToDeployTo == null) + { + _logger.LogError("Environment to deploy to was not found"); + return 1; + } - var deployMappingSchemaResponse = await _mediator.Send(new DeployMappingSchemaRequest() + var createReleaseResponse = await _mediator.Send(new CreateReleaseRequest + { + EnvironmentId = environmentToDeployTo.Id.IdValue, + Schemas = new[] { - SchemaId = mappingSchemaId.IdValue, - Deployments = new List() + new SchemaVersionId { - new DeployMappingSchemaRequest.EnvironmentSchemaDeployment() - { - Version = existingSchema.Version.Id.Version, - EnvironmentId = environmentToDeployTo.Id.IdValue - } + SchemaId = mappingSchemaId.IdValue, + Version = existingSchema.Version.Id.Version } - }); - - if (!deployMappingSchemaResponse.Success) - { - var error = JsonSerializer.Serialize(deployMappingSchemaResponse.Error); - _logger.LogError("Something went wrong when deploying schema: " + error); - return 1; } + }); - _deploymentPlanFileService.UpdateDeploymentPlan(Alias, existingSchema.LatestVersion); - - _outputService.Write("Successfully deployed schema: " + Alias); + if (!createReleaseResponse.Success) + { + LogError(createReleaseResponse.Error); - return 0; + return 1; } - private async Task GetEnvironmentToDeployTo() - { - var environments = await _mediator.Send(new GetEnvironmentsRequest()); - var environmentToDeployTo = environments.FirstOrDefault(e => e.Name == Environment); - return environmentToDeployTo; - } + _deploymentPlanFileService.UpdateDeploymentPlan(Alias, existingSchema.LatestVersion); - private async Task ValidateMappingSchema(GetMappingSchemaResponse existingSchema, string mappingSchemaGuid) - { - var validationResponse = await _mediator.Send(new ValidateMappingSchemaRequest() + _outputService.Write("Successfully deployed schema: " + Alias); + + return 0; + } + + private async Task GetEnvironmentToDeployTo() + { + var environments = await _mediator.Send(new GetEnvironmentsRequest()); + var environmentToDeployTo = environments.FirstOrDefault(e => e.Name == Environment); + return environmentToDeployTo; + } + + private async Task GetExistingSchema(string mappingSchemaGuid) + { + var existingSchema = await _mediator.Send( + new GetMappingSchemaRequest { - Version = existingSchema.LatestVersion, - MappingSchemaId = mappingSchemaGuid, - }); + MappingSchemaId = mappingSchemaGuid + } + ); - return validationResponse; - } + return existingSchema; + } - private async Task GetExistingSchema(string mappingSchemaGuid) - { - var existingSchema = await _mediator.Send( - new GetMappingSchemaRequest - { - MappingSchemaId = mappingSchemaGuid - } - ); + private async Task GetMappingSchemaGuid() + { + var schemas = await _mediator.Send(new QueryMappingSchemasRequest()); + var mappingSchemaGuid = schemas.FirstOrDefault(sc => sc.ViewHandle == Alias)?.Id; + return mappingSchemaGuid; + } - return existingSchema; + private void LogError(ApiErrorBaseResponse apiErrorBaseResponse) + { + if (apiErrorBaseResponse is ApiGroupedErrorResponse apiGroupedErrorResponse) + { + foreach (var groupedError in apiGroupedErrorResponse.Errors) + { + var error = JsonSerializer.Serialize(groupedError.Errors); + _logger.LogError("Something went wrong when deploying schema with id '" + groupedError.Name + "': " + error); + } } - - private async Task GetMappingSchemaGuid() + else { - var schemas = await _mediator.Send(new QueryMappingSchemasRequest()); - var mappingSchemaGuid = schemas.FirstOrDefault(sc => sc.ViewHandle == Alias)?.Id; - return mappingSchemaGuid; + var error = JsonSerializer.Serialize((ApiErrorResponse)apiErrorBaseResponse); + _logger.LogError("Something went wrong when deploying schema: " + error); } } } diff --git a/src/Enterspeed.Cli/Commands/Schema/ImportSchemaCommand.cs b/src/Enterspeed.Cli/Commands/Schema/ImportSchemaCommand.cs index 3662379..acbe451 100644 --- a/src/Enterspeed.Cli/Commands/Schema/ImportSchemaCommand.cs +++ b/src/Enterspeed.Cli/Commands/Schema/ImportSchemaCommand.cs @@ -2,6 +2,7 @@ using System.CommandLine.Invocation; using System.Text.Json; using Enterspeed.Cli.Api.MappingSchema; +using Enterspeed.Cli.Extensions; using Enterspeed.Cli.Services.ConsoleOutput; using Enterspeed.Cli.Services.FileService; using Enterspeed.Cli.Services.FileService.Models; @@ -117,7 +118,8 @@ private async Task CreateNewSchema(SchemaFile schemaFile) var createSchemaResponse = await _mediator.Send(new CreateMappingSchemaRequest { Name = schemaFile.Alias, - ViewHandle = schemaFile.Alias + ViewHandle = schemaFile.Alias, + Type = schemaFile.SchemaType.ToApiString() }); if (createSchemaResponse?.IdValue is null || string.IsNullOrEmpty(createSchemaResponse.MappingSchemaGuid)) diff --git a/src/Enterspeed.Cli/Domain/Models/ApiErrorResponse.cs b/src/Enterspeed.Cli/Domain/Models/ApiErrorResponse.cs index d6d9fc2..3a85a3e 100644 --- a/src/Enterspeed.Cli/Domain/Models/ApiErrorResponse.cs +++ b/src/Enterspeed.Cli/Domain/Models/ApiErrorResponse.cs @@ -3,7 +3,7 @@ namespace Enterspeed.Cli.Domain.Models; -public class ApiErrorResponse +public class ApiErrorBaseResponse { [JsonPropertyName("status")] public int Status { get; set; } @@ -13,8 +13,28 @@ public class ApiErrorResponse public string Code { get; set; } [JsonPropertyName("detail")] public string Detail { get; set; } +} + +public class ApiErrorResponse : ApiErrorBaseResponse +{ [JsonPropertyName("errors")] public ExpandoObject Errors { get; set; } [JsonPropertyName("warnings")] public ExpandoObject Warnings { get; set; } } + +public class ApiGroupedErrorResponse : ApiErrorBaseResponse +{ + [JsonPropertyName("errors")] + public GroupedError[] Errors { get; set; } + [JsonPropertyName("warnings")] + public GroupedError[] Warnings { get; set; } +} + +public class GroupedError +{ + [JsonPropertyName("name")] + public string Name { get; set; } + [JsonPropertyName("errors")] + public ExpandoObject Errors { get; set; } +} diff --git a/src/Enterspeed.Cli/Domain/Models/ErrorCode.cs b/src/Enterspeed.Cli/Domain/Models/ErrorCode.cs new file mode 100644 index 0000000..91bf2f3 --- /dev/null +++ b/src/Enterspeed.Cli/Domain/Models/ErrorCode.cs @@ -0,0 +1,7 @@ +namespace Enterspeed.Cli.Domain.Models +{ + public static class ErrorCode + { + public static string FailedToCreateRelease = "FailedToCreateRelease"; + } +} diff --git a/src/Enterspeed.Cli/Domain/Models/SchemaType.cs b/src/Enterspeed.Cli/Domain/Models/SchemaType.cs new file mode 100644 index 0000000..3e74196 --- /dev/null +++ b/src/Enterspeed.Cli/Domain/Models/SchemaType.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Enterspeed.Cli.Domain.Models; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum SchemaType +{ + Normal, + Partial +} \ No newline at end of file diff --git a/src/Enterspeed.Cli/Extensions/SchemaTypeExtensions.cs b/src/Enterspeed.Cli/Extensions/SchemaTypeExtensions.cs new file mode 100644 index 0000000..e47be40 --- /dev/null +++ b/src/Enterspeed.Cli/Extensions/SchemaTypeExtensions.cs @@ -0,0 +1,11 @@ +using Enterspeed.Cli.Domain.Models; + +namespace Enterspeed.Cli.Extensions; + +public static class SchemaTypeExtensions +{ + public static string ToApiString(this SchemaType schemaType) + { + return schemaType.ToString().ToLower(); + } +} \ No newline at end of file diff --git a/src/Enterspeed.Cli/Services/EnterspeedClient/EnterspeedClient.cs b/src/Enterspeed.Cli/Services/EnterspeedClient/EnterspeedClient.cs index 24a7d24..2b25166 100644 --- a/src/Enterspeed.Cli/Services/EnterspeedClient/EnterspeedClient.cs +++ b/src/Enterspeed.Cli/Services/EnterspeedClient/EnterspeedClient.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Reflection; using System.Text.Json; using Enterspeed.Cli.Api.Identity.Models; using Enterspeed.Cli.Configuration; @@ -85,6 +86,8 @@ public async Task ExecuteAsync(RestRequest request, CancellationTo private void AddHeaders(RestRequest request) { + request.AddHeader("X-Enterspeed-System", $"cli/{GetVersionNumber()}"); + if (!string.IsNullOrEmpty(_apiKeyValue)) { request.AddHeader("X-Api-Key", _apiKeyValue); @@ -199,6 +202,11 @@ private async Task RefreshToken(string refreshToken) }); } + private static string GetVersionNumber() + { + return Assembly.GetExecutingAssembly().GetName().Version?.ToString(3); + } + public void Dispose() { _client?.Dispose(); diff --git a/src/Enterspeed.Cli/Services/FileService/ISchemaFileService.cs b/src/Enterspeed.Cli/Services/FileService/ISchemaFileService.cs index 90fc3ef..a7f6679 100644 --- a/src/Enterspeed.Cli/Services/FileService/ISchemaFileService.cs +++ b/src/Enterspeed.Cli/Services/FileService/ISchemaFileService.cs @@ -1,10 +1,11 @@ -using Enterspeed.Cli.Services.FileService.Models; +using Enterspeed.Cli.Domain.Models; +using Enterspeed.Cli.Services.FileService.Models; namespace Enterspeed.Cli.Services.FileService; public interface ISchemaFileService { - void CreateSchema(string alias, string content = null); + void CreateSchema(string alias, SchemaType schemaType, string content = null); SchemaFile GetSchema(string alias, string filePath = null); IList GetAllSchemas(); bool SchemaExists(string alias); diff --git a/src/Enterspeed.Cli/Services/FileService/Models/SchemaFile.cs b/src/Enterspeed.Cli/Services/FileService/Models/SchemaFile.cs index 4d7be07..135bfa7 100644 --- a/src/Enterspeed.Cli/Services/FileService/Models/SchemaFile.cs +++ b/src/Enterspeed.Cli/Services/FileService/Models/SchemaFile.cs @@ -1,13 +1,17 @@ -namespace Enterspeed.Cli.Services.FileService.Models; +using Enterspeed.Cli.Domain.Models; + +namespace Enterspeed.Cli.Services.FileService.Models; public class SchemaFile { public string Alias { get; } + public SchemaType SchemaType { get; } public SchemaBaseProperties SchemaBaseProperties { get; } - public SchemaFile(string alias, SchemaBaseProperties schemaBaseProperties) + public SchemaFile(string alias, SchemaType schemaType, SchemaBaseProperties schemaBaseProperties) { Alias = alias; + SchemaType = schemaType; SchemaBaseProperties = schemaBaseProperties; } } \ No newline at end of file diff --git a/src/Enterspeed.Cli/Services/FileService/SchemaFileService.cs b/src/Enterspeed.Cli/Services/FileService/SchemaFileService.cs index e4fb597..0bfba1a 100644 --- a/src/Enterspeed.Cli/Services/FileService/SchemaFileService.cs +++ b/src/Enterspeed.Cli/Services/FileService/SchemaFileService.cs @@ -1,155 +1,182 @@ using System.Text.Json; using System.Text.Json.Serialization; using Enterspeed.Cli.Domain; +using Enterspeed.Cli.Domain.Models; using Enterspeed.Cli.Services.FileService.Models; using Microsoft.Extensions.Logging; -namespace Enterspeed.Cli.Services.FileService +namespace Enterspeed.Cli.Services.FileService; + +public class SchemaFileService : ISchemaFileService { - public class SchemaFileService : ISchemaFileService + private readonly ILogger _logger; + private const string SchemaDirectory = "schemas"; + // logic require partial folder to be a subfolder of normal schema folder + private const string PartialSchemaDirectory = $"{SchemaDirectory}/partials"; + public static readonly JsonSerializerOptions SerializerOptions = new() { - private readonly ILogger _logger; - private const string SchemaDirectory = "schemas"; - public static readonly JsonSerializerOptions SerializerOptions = new() - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }; - - public SchemaFileService(ILogger logger) - { - _logger = logger; - } + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; - public void CreateSchema(string alias, string content = null) - { - EnsureSchemaFolder(); + public SchemaFileService(ILogger logger) + { + _logger = logger; + } - if (SchemaExists(alias)) - { - _logger.LogWarning($"Schema {alias} exists on disk. Recreating."); - DeleteSchema(alias); - } + public void CreateSchema(string alias, SchemaType schemaType, string content = null) + { + EnsureSchemaFolders(); - if (content == null) - { - CreateEmptySchema(alias); - } - else - { - CreatePopulatedSchema(alias, content); - } + if (SchemaExists(alias)) + { + _logger.LogWarning($"Schema {alias} exists on disk. Recreating."); + DeleteSchema(alias); } - private void CreateEmptySchema(string alias) + if (content == null) { - CreateSchema(alias, new SchemaBaseProperties - { - Properties = new(), - Triggers = new() - }); + CreateEmptySchema(alias, schemaType); } - - private void CreatePopulatedSchema(string alias, string content) + else { - CreateSchema(alias, JsonSerializer.Deserialize(content, SerializerOptions)); + CreatePopulatedSchema(alias, schemaType, content); } + } - private void CreateSchema(string alias, SchemaBaseProperties content) - { - using (var fs = File.Create(GetFilePath(alias))) - { - _logger.LogInformation("Creating schema"); + private void CreateEmptySchema(string alias, SchemaType schemaType) + { + var content = schemaType == SchemaType.Partial + ? new SchemaBaseProperties { Properties = new() } + : new SchemaBaseProperties { Properties = new(), Triggers = new() }; - var jsonBytes = JsonSerializer.SerializeToUtf8Bytes(content, SerializerOptions); - fs.Write(jsonBytes, 0, jsonBytes.Length); - } - } + CreateSchema(alias, schemaType, content); + } + + private void CreatePopulatedSchema(string alias, SchemaType schemaType, string content) + { + CreateSchema(alias, schemaType, JsonSerializer.Deserialize(content, SerializerOptions)); + } - public SchemaFile GetSchema(string alias, string filePath = null) + private void CreateSchema(string alias, SchemaType schemaType, SchemaBaseProperties content) + { + using (var fs = File.Create(GetRelativeFilePath(alias, schemaType))) { - var schemaFile = GetSchemaContent(alias, filePath); - var schemaBaseProperties = JsonSerializer.Deserialize(schemaFile, SerializerOptions); + _logger.LogInformation("Creating schema"); - return new SchemaFile(alias, schemaBaseProperties); + var jsonBytes = JsonSerializer.SerializeToUtf8Bytes(content, SerializerOptions); + fs.Write(jsonBytes, 0, jsonBytes.Length); } + } - public IList GetAllSchemas() - { - EnsureSchemaFolder(); + public SchemaFile GetSchema(string alias, string filePath = null) + { + var schemaFilePath = filePath ?? GetFile(alias); + var schemaFolderName = Path.GetFileName(Path.GetDirectoryName(schemaFilePath)); + var partialSchemaFolderName = Path.GetFileName(Path.GetDirectoryName($"{PartialSchemaDirectory}/")); + var schemaContent = GetSchemaContent(alias, schemaFilePath); + + var schemaType = schemaFolderName == partialSchemaFolderName ? SchemaType.Partial : SchemaType.Normal; + var schemaBaseProperties = JsonSerializer.Deserialize(schemaContent, SerializerOptions); + + return new SchemaFile(alias, schemaType, schemaBaseProperties); + } + + public IList GetAllSchemas() + { + EnsureSchemaFolders(); - var filePaths = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), SchemaDirectory)); + var filePaths = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), SchemaDirectory), "*", SearchOption.AllDirectories); - return filePaths.Select(filePath => + return filePaths.Select(filePath => { var alias = GetAliasFromFilePath(filePath); return GetSchema(alias, filePath); }) .ToList(); - } + } - public bool SchemaValid(string externalSchema, string schemaAlias) + public bool SchemaValid(string externalSchema, string schemaAlias) + { + if (!SchemaExists(schemaAlias)) { - if (!SchemaExists(schemaAlias)) - { - return false; - } - - var localSchema = GetSchemaContent(schemaAlias); - return CompareSchemaContent(externalSchema, localSchema); + return false; } + + var localSchema = GetSchemaContent(schemaAlias); + return CompareSchemaContent(externalSchema, localSchema); + } - public bool SchemaExists(string alias) - { - var schemaFilePath = GetFilePath(alias); - return File.Exists(Path.Combine(Directory.GetCurrentDirectory(), schemaFilePath)); - } + public bool SchemaExists(string alias) + { + return GetFile(alias) is not null; + } - private static void EnsureSchemaFolder() + private static void EnsureSchemaFolders() + { + if (!Directory.Exists(SchemaDirectory)) { - if (!Directory.Exists(SchemaDirectory)) - { - Directory.CreateDirectory(SchemaDirectory); - } + Directory.CreateDirectory(SchemaDirectory); } - private static void DeleteSchema(string alias) + if (!Directory.Exists(PartialSchemaDirectory)) { - var schemaFilePath = GetFilePath(alias); - File.Delete(schemaFilePath); + Directory.CreateDirectory(PartialSchemaDirectory); } + } - private static string GetSchemaContent(string alias, string filePath = null) + private static void DeleteSchema(string alias) + { + var file = GetFile(alias); + if (file is not null) { - var schemaFilePath = filePath ?? GetFilePath(alias); - return File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), schemaFilePath)); + File.Delete(file); } + } - private static string GetFilePath(string alias) - { - return $"{SchemaDirectory}/{alias}.json"; - } + private static string GetSchemaContent(string alias, string filePath = null) + { + var schemaFilePath = filePath ?? GetFile(alias); + return File.ReadAllText(schemaFilePath); + } + + private static string GetRelativeFilePath(string alias, SchemaType schemaType) + { + return schemaType == SchemaType.Normal + ? Path.Combine(SchemaDirectory, GetFileName(alias)) + : Path.Combine(PartialSchemaDirectory, GetFileName(alias)); + } + + private static string GetFileName(string alias) + { + return $"{alias}.json"; + } + + private static string GetFile(string alias) + { + var schemaFileName = GetFileName(alias); + return Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), SchemaDirectory), schemaFileName, SearchOption.AllDirectories).FirstOrDefault(); + } + + private static string GetAliasFromFilePath(string filePath) + { + return Path.GetFileNameWithoutExtension(filePath); + } - private static string GetAliasFromFilePath(string filePath) + private bool CompareSchemaContent(string schema1, string schema2) + { + var comparer = new JsonElementComparer(); + try { - return Path.GetFileNameWithoutExtension(filePath); + using var doc1 = JsonDocument.Parse(schema1); + using var doc2 = JsonDocument.Parse(schema2); + return comparer.Equals(doc1.RootElement, doc2.RootElement); } - - private bool CompareSchemaContent(string schema1, string schema2) + catch (Exception ex) { - var comparer = new JsonElementComparer(); - try - { - using var doc1 = JsonDocument.Parse(schema1); - using var doc2 = JsonDocument.Parse(schema2); - return comparer.Equals(doc1.RootElement, doc2.RootElement); - } - catch (Exception ex) - { - _logger.LogError($"Could not deserialize schema! {ex.Message}"); - } - - return false; + _logger.LogError($"Could not deserialize schema! {ex.Message}"); } + + return false; } -} +} \ No newline at end of file