Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ship two json schema files.. One that reference others, and a CMS one #13123

Merged
merged 4 commits into from
Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,8 @@ cypress.env.json
# Ignore auto-generated schema
/src/Umbraco.Cms.Targets/appsettings-schema.json
/src/Umbraco.Web.UI/appsettings-schema.json
/src/Umbraco.Web.UI/appsettings-schema.umbraco.json
/tests/Umbraco.Tests.Integration/appsettings-schema.json
/src/Umbraco.Cms.Targets/appsettings-schema.json
/src/Umbraco.Cms.Targets/appsettings-schema.umbraco.json

133 changes: 37 additions & 96 deletions src/JsonSchema/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,133 +3,74 @@

using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Deploy.Core.Configuration.DebugConfiguration;
using Umbraco.Deploy.Core.Configuration.DeployConfiguration;
using Umbraco.Deploy.Core.Configuration.DeployProjectConfiguration;
using Umbraco.Forms.Core.Configuration;
using SecuritySettings = Umbraco.Cms.Core.Configuration.Models.SecuritySettings;

namespace JsonSchema
{
internal class AppSettings
{
/// <summary>
/// Gets or sets the Umbraco
/// </summary>
public UmbracoDefinition? Umbraco { get; set; }

/// <summary>
/// Configuration of Umbraco CMS and packages
/// </summary>
internal class UmbracoDefinition
{
// ReSharper disable once InconsistentNaming
public CmsDefinition? CMS { get; set; }

public FormsDefinition? Forms { get; set; }
namespace JsonSchema;

public DeployDefinition? Deploy { get; set; }
internal class AppSettings
{
// ReSharper disable once InconsistentNaming
public CmsDefinition? CMS { get; set; }

/// <summary>
/// Configurations for the Umbraco CMS
/// </summary>
public class CmsDefinition
{
public ContentSettings? Content { get; set; }
public CoreDebugSettings? Debug { get; set; }
/// <summary>
/// Configurations for the Umbraco CMS
/// </summary>
public class CmsDefinition
{
public ContentSettings? Content { get; set; }
public CoreDebugSettings? Debug { get; set; }

public ExceptionFilterSettings? ExceptionFilter { get; set; }
public ExceptionFilterSettings? ExceptionFilter { get; set; }

public ModelsBuilderSettings? ModelsBuilder { get; set; }
public ModelsBuilderSettings? ModelsBuilder { get; set; }

public GlobalSettings? Global { get; set; }
public GlobalSettings? Global { get; set; }

public HealthChecksSettings? HealthChecks { get; set; }
public HealthChecksSettings? HealthChecks { get; set; }

public HostingSettings? Hosting { get; set; }
public HostingSettings? Hosting { get; set; }

public ImagingSettings? Imaging { get; set; }
public ImagingSettings? Imaging { get; set; }

public IndexCreatorSettings? Examine { get; set; }
public IndexCreatorSettings? Examine { get; set; }

public KeepAliveSettings? KeepAlive { get; set; }
public KeepAliveSettings? KeepAlive { get; set; }

public LoggingSettings? Logging { get; set; }
public LoggingSettings? Logging { get; set; }

public NuCacheSettings? NuCache { get; set; }

public RequestHandlerSettings? RequestHandler { get; set; }
public RequestHandlerSettings? RequestHandler { get; set; }

public RuntimeSettings? Runtime { get; set; }
public RuntimeSettings? Runtime { get; set; }

public SecuritySettings? Security { get; set; }
public SecuritySettings? Security { get; set; }

public TourSettings? Tours { get; set; }
public TourSettings? Tours { get; set; }

public TypeFinderSettings? TypeFinder { get; set; }
public TypeFinderSettings? TypeFinder { get; set; }

public WebRoutingSettings? WebRouting { get; set; }

public UmbracoPluginSettings? Plugins { get; set; }

public UnattendedSettings? Unattended { get; set; }

public RichTextEditorSettings? RichTextEditor { get; set; }

public RuntimeMinificationSettings? RuntimeMinification { get; set; }

public BasicAuthSettings? BasicAuth { get; set; }

public PackageMigrationSettings? PackageMigration { get; set; }

public LegacyPasswordMigrationSettings? LegacyPasswordMigration { get; set; }

public ContentDashboardSettings? ContentDashboard { get; set; }

public HelpPageSettings? HelpPage { get; set; }

public InstallDefaultDataSettings? DefaultDataCreation { get; set; }

public DataTypesSettings? DataTypes { get; set; }
}
public UmbracoPluginSettings? Plugins { get; set; }

/// <summary>
/// Configurations for the Umbraco Forms package to Umbraco CMS
/// </summary>
public class FormsDefinition
{
public FormDesignSettings? FormDesign { get; set; }
public UnattendedSettings? Unattended { get; set; }

public PackageOptionSettings? Options { get; set; }
public RichTextEditorSettings? RichTextEditor { get; set; }

public Umbraco.Forms.Core.Configuration.SecuritySettings? Security { get; set; }
public RuntimeMinificationSettings? RuntimeMinification { get; set; }

public FieldTypesDefinition? FieldTypes { get; set; }
public BasicAuthSettings? BasicAuth { get; set; }

/// <summary>
/// Configurations for the Umbraco Forms Field Types
/// </summary>
public class FieldTypesDefinition
{
public DatePickerSettings? DatePicker { get; set; }
public PackageMigrationSettings? PackageMigration { get; set; }

public Recaptcha2Settings? Recaptcha2 { get; set; }
public LegacyPasswordMigrationSettings? LegacyPasswordMigration { get; set; }

public Recaptcha3Settings? Recaptcha3 { get; set; }
}
}
public ContentDashboardSettings? ContentDashboard { get; set; }

/// <summary>
/// Configurations for the Umbraco Deploy package to Umbraco CMS
/// </summary>
public class DeployDefinition
{
public DeploySettings? Settings { get; set; }
public HelpPageSettings? HelpPage { get; set; }

public DeployProjectConfig? Project { get; set; }
public InstallDefaultDataSettings? DefaultDataCreation { get; set; }

public DebugSettings? Debug { get; set; }
}
}
public DataTypesSettings? DataTypes { get; set; }
}
}
18 changes: 18 additions & 0 deletions src/JsonSchema/JsonSchema.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,29 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="NJsonSchema" Version="10.8.0" />
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
<PackageReference Include="Umbraco.Deploy.Core" Version="10.1.0" />
<PackageReference Include="Umbraco.Forms.Core" Version="10.1.0" />
</ItemGroup>

<ItemGroup>
<None Remove="appsettings-schema.json" />
<EmbeddedResource Include="appsettings-schema.json" />
</ItemGroup>

<!-- Copy Forms XML docs-->
<PropertyGroup>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
</PropertyGroup>

<Target Name="CopyPackagesXml" BeforeTargets="Build">
<ItemGroup>
<PackageReferenceFiles Include="$(NugetPackageRoot)%(PackageReference.Identity)\%(PackageReference.Version)%(PackageReference.CopyToOutputDirectory)\lib\**\*.xml" />
</ItemGroup>
<Copy SourceFiles="@(PackageReferenceFiles)" DestinationFolder="$(OutDir)" />
</Target>
</Project>
7 changes: 5 additions & 2 deletions src/JsonSchema/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ namespace JsonSchema
{
internal class Options
{
[Option('o', "outputFile", Required = false, HelpText = "Set path of the output file.", Default = "appsettings-schema.json")]
public string OutputFile { get; set; } = null!;
[Option('m', "mainOutputFile", Required = false, HelpText = "Set path of the main output file.", Default = "../../../../Umbraco.Web.UI/appsettings-schema.json")]
public string MainOutputFile { get; set; } = null!;

[Option('f', "cmsOutputFile", Required = false, HelpText = "Set path of the cms output file.", Default = "../../../../Umbraco.Web.UI/appsettings-schema.umbraco.json")]
public string CmsOutputFile { get; set; } = null!;
}
}
20 changes: 14 additions & 6 deletions src/JsonSchema/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,23 @@ await Parser.Default.ParseArguments<Options>(args)
private static async Task Execute(Options options)
{
var generator = new UmbracoJsonSchemaGenerator();
var schema = await generator.Generate();

var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, options.OutputFile));
Console.WriteLine("Path to use {0}", path);
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
var cmsSchema = await generator.GenerateCmsFile();
await WriteSchemaToFile(cmsSchema, options.CmsOutputFile);

var schema = await generator.GenerateMainFile();
await WriteSchemaToFile(schema, options.MainOutputFile);
}

private static async Task WriteSchemaToFile(string schema, string filePath)
{
var mainPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, filePath));
Console.WriteLine("Path to use {0}", mainPath);
Directory.CreateDirectory(Path.GetDirectoryName(mainPath)!);
Console.WriteLine("Ensured directory exists");
await File.WriteAllTextAsync(path, schema);
await File.WriteAllTextAsync(mainPath, schema);

Console.WriteLine("File written at {0}", path);
Console.WriteLine("File written at {0}", mainPath);
}
}
}
95 changes: 60 additions & 35 deletions src/JsonSchema/UmbracoJsonSchemaGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,58 +1,83 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.

using Microsoft.Extensions.FileProviders;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NJsonSchema.Generation;
using Umbraco.Cms.Core.Configuration.Models;

namespace JsonSchema
namespace JsonSchema;

/// <summary>
/// Generator of the JsonSchema for AppSettings.json including A specific Umbraco version.
/// </summary>
public class UmbracoJsonSchemaGenerator
{
private static readonly HttpClient s_client = new();
private readonly JsonSchemaGenerator _innerGenerator;

/// <summary>
/// Generator of the JsonSchema for AppSettings.json including A specific Umbraco version.
/// Initializes a new instance of the <see cref="UmbracoJsonSchemaGenerator" /> class.
/// </summary>
public class UmbracoJsonSchemaGenerator
public UmbracoJsonSchemaGenerator()
=> _innerGenerator = new JsonSchemaGenerator(new UmbracoJsonSchemaGeneratorSettings());

/// <summary>
/// Generates a json representing the JsonSchema for AppSettings.json including A specific Umbraco version..
/// </summary>
public async Task<string> GenerateMainFile()
{
private static readonly HttpClient s_client = new ();
private readonly JsonSchemaGenerator _innerGenerator;

/// <summary>
/// Initializes a new instance of the <see cref="UmbracoJsonSchemaGenerator" /> class.
/// </summary>
public UmbracoJsonSchemaGenerator()
=> _innerGenerator = new JsonSchemaGenerator(new UmbracoJsonSchemaGeneratorSettings());

/// <summary>
/// Generates a json representing the JsonSchema for AppSettings.json including A specific Umbraco version..
/// </summary>
public async Task<string> Generate()
{
JObject umbracoSchema = GenerateUmbracoSchema();
JObject officialSchema = await GetOfficialAppSettingsSchema();
JObject officialSchema = await GetOfficialAppSettingsSchema();
JObject externalFilePoints = GenerateSchemaWithExternalDefinitions();

officialSchema.Merge(umbracoSchema);
officialSchema.Merge(externalFilePoints);

return officialSchema.ToString();
}
return officialSchema.ToString();
}

private async Task<JObject> GetOfficialAppSettingsSchema()
{
HttpResponseMessage response = await s_client.GetAsync("https://json.schemastore.org/appsettings.json")
.ConfigureAwait(false);

var result = await response.Content.ReadAsStringAsync();
/// <summary>
/// Generates the CMS file
/// </summary>
/// <returns></returns>
public Task<string> GenerateCmsFile()
{
JObject cmsSchema = GenerateUmbracoSchema();

return JsonConvert.DeserializeObject<JObject>(result)!;
}
return Task.FromResult(cmsSchema.ToString());
}

private JObject GenerateUmbracoSchema()
{
NJsonSchema.JsonSchema schema = _innerGenerator.Generate(typeof(AppSettings));

// TODO: when the "UmbracoPath" setter is removed from "GlobalSettings" (scheduled for V12), remove this line as well
schema.Definitions["UmbracoCmsCoreConfigurationModelsGlobalSettings"]?.Properties?.Remove(nameof(GlobalSettings.UmbracoPath));

return JsonConvert.DeserializeObject<JObject>(schema.ToJson())!;
private JObject GenerateSchemaWithExternalDefinitions()
{
var fileProvider = new EmbeddedFileProvider(GetType().Assembly);

IFileInfo schema = fileProvider.GetFileInfo("appsettings-schema.json");

using (Stream? stream = schema.CreateReadStream())
using (var reader = new StreamReader(stream))
{
return JsonConvert.DeserializeObject<JObject>(reader.ReadToEnd())!;
}
}

private async Task<JObject> GetOfficialAppSettingsSchema()
{
HttpResponseMessage response = await s_client.GetAsync("https://json.schemastore.org/appsettings.json")
.ConfigureAwait(false);

var result = await response.Content.ReadAsStringAsync();

return JsonConvert.DeserializeObject<JObject>(result)!;
}

private JObject GenerateUmbracoSchema()
{
NJsonSchema.JsonSchema schema = _innerGenerator.Generate(typeof(AppSettings));

// TODO: when the "UmbracoPath" setter is removed from "GlobalSettings" (scheduled for V12), remove this line as well
schema.Definitions["UmbracoCmsCoreConfigurationModelsGlobalSettings"]?.Properties?.Remove(nameof(GlobalSettings.UmbracoPath));return JsonConvert.DeserializeObject<JObject>(schema.ToJson())!;
}
}
Loading