From 60ae934d397b1b9bf69d93635d08341b3680a0c4 Mon Sep 17 00:00:00 2001 From: abaskk-msft Date: Fri, 31 May 2024 17:04:42 -0700 Subject: [PATCH 01/11] CLI scaffolding for YAMLValidator (#661) --- src/PASopa.sln | 6 ++ src/YAMLValidator/InputProcessor.cs | 105 +++++++++++++++++++++++++ src/YAMLValidator/Program.cs | 15 ++++ src/YAMLValidator/YAMLValidator.csproj | 19 +++++ 4 files changed, 145 insertions(+) create mode 100644 src/YAMLValidator/InputProcessor.cs create mode 100644 src/YAMLValidator/Program.cs create mode 100644 src/YAMLValidator/YAMLValidator.csproj diff --git a/src/PASopa.sln b/src/PASopa.sln index 35b00095..63347bf4 100644 --- a/src/PASopa.sln +++ b/src/PASopa.sln @@ -20,6 +20,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Pow EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence.Tests", "Persistence.Tests\Persistence.Tests.csproj", "{8AB1C901-FE5E-44BF-AA21-B8F20A9D7CDD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YAMLValidator", "YAMLValidator\YAMLValidator.csproj", "{F0AD11CE-E634-4945-A6B1-7866CDE0059C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -46,6 +48,10 @@ Global {8AB1C901-FE5E-44BF-AA21-B8F20A9D7CDD}.Debug|Any CPU.Build.0 = Debug|Any CPU {8AB1C901-FE5E-44BF-AA21-B8F20A9D7CDD}.Release|Any CPU.ActiveCfg = Release|Any CPU {8AB1C901-FE5E-44BF-AA21-B8F20A9D7CDD}.Release|Any CPU.Build.0 = Release|Any CPU + {F0AD11CE-E634-4945-A6B1-7866CDE0059C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0AD11CE-E634-4945-A6B1-7866CDE0059C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0AD11CE-E634-4945-A6B1-7866CDE0059C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0AD11CE-E634-4945-A6B1-7866CDE0059C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YAMLValidator/InputProcessor.cs new file mode 100644 index 00000000..6c62315a --- /dev/null +++ b/src/YAMLValidator/InputProcessor.cs @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.CommandLine; + +namespace YAMLValidator; +internal sealed class InputProcessor +{ + public static RootCommand GetRootCommand() + { + + const string FileTypeName = "file"; + const string FolderTypeName = "folder"; + const string YamlFileExtension = ".yaml"; + const string JsonFileExtension = ".json"; + + var pathOption = new Option( + name: "--path", + description: "The path to the input yaml file or directory of yaml files" + ) + { IsRequired = true }; + + pathOption.AddValidator(result => + { + var inputFilePath = result.GetValueForOption(pathOption); + + // either file or folder must be passed + var pathType = string.Empty; + if (string.IsNullOrEmpty(inputFilePath)) + { + result.ErrorMessage = "The input is invalid, input must be a filepath to a yaml file or a folder path to a folder of yaml files"; + } + else if (!Directory.Exists(inputFilePath) && !File.Exists(inputFilePath)) + { + result.ErrorMessage = "The input path does not exist"; + } + else if (Directory.Exists(inputFilePath)) + { + if (Directory.GetFiles(inputFilePath, $"*{YamlFileExtension}").Length == 0) + { + result.ErrorMessage = "The input folder does not contain any yaml files"; + } + } + else if (File.Exists(inputFilePath)) + { + if (Path.GetExtension(inputFilePath) != YamlFileExtension) + { + result.ErrorMessage = "The input file must be a yaml file"; + } + } + }); + + var schemaOption = new Option( + name: "--schema", + description: "The path to the schema json file", + // assume local schema file exists in nuget package, use relative filepath for now + getDefaultValue: () => @"..\schemas\pa-yaml\v3.0\pa.yaml-schema.json" + ); + + schemaOption.AddValidator(result => + { + var schemaPath = result.GetValueForOption(schemaOption); + if (string.IsNullOrEmpty(schemaPath)) + { + result.ErrorMessage = "Schema option selected, but no schema was provided"; + } + else if (Path.GetExtension(schemaPath) != JsonFileExtension) + { + result.ErrorMessage = "The schema file must be a json file"; + } + else if (!File.Exists(schemaPath)) + { + result.ErrorMessage = "The schema file does not exist"; + } + + }); + + // define root + var rootCommand = new RootCommand("YAML validator cli-tool"); + + // validate command + var validateCommand = new Command("validate", "Validate the input yaml file") + { + pathOption, + schemaOption + }; + + validateCommand.SetHandler((pathOptionVal, schemaOptionVal) => + { + // validation has completed, we either have a file or folder + var fileType = File.Exists(pathOptionVal) ? FileTypeName : FolderTypeName; + Console.WriteLine($"ValidatingPath: {pathOptionVal}"); + Console.WriteLine($"Path type: {fileType}"); + Console.WriteLine($"Schema: {schemaOptionVal}"); + + // to do -> add handler to validate all yaml files in a folder are actually parseable as yaml + // or add handler to validate a single yaml file is parseable as yaml + }, pathOption, schemaOption); + + rootCommand.AddCommand(validateCommand); + + return rootCommand; + + } +} diff --git a/src/YAMLValidator/Program.cs b/src/YAMLValidator/Program.cs new file mode 100644 index 00000000..a43d4227 --- /dev/null +++ b/src/YAMLValidator/Program.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.CommandLine; + +namespace YAMLValidator; + +internal sealed class Program +{ + private static void Main(String[] args) + { + var inputProcessor = InputProcessor.GetRootCommand(); + inputProcessor.Invoke(args); + } +} diff --git a/src/YAMLValidator/YAMLValidator.csproj b/src/YAMLValidator/YAMLValidator.csproj new file mode 100644 index 00000000..0dae98fa --- /dev/null +++ b/src/YAMLValidator/YAMLValidator.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + From 41b143b76b74ae5152a085da29d9539aaf6444c2 Mon Sep 17 00:00:00 2001 From: Amruth Baskar Date: Tue, 4 Jun 2024 14:59:39 -0700 Subject: [PATCH 02/11] Fixed spacing and namespace --- src/YAMLValidator/InputProcessor.cs | 5 ++--- src/YAMLValidator/Program.cs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YAMLValidator/InputProcessor.cs index 6c62315a..c84b1387 100644 --- a/src/YAMLValidator/InputProcessor.cs +++ b/src/YAMLValidator/InputProcessor.cs @@ -3,7 +3,7 @@ using System.CommandLine; -namespace YAMLValidator; +namespace Microsoft.PowerPlatform.PowerApps.Persistence; internal sealed class InputProcessor { public static RootCommand GetRootCommand() @@ -55,7 +55,7 @@ public static RootCommand GetRootCommand() description: "The path to the schema json file", // assume local schema file exists in nuget package, use relative filepath for now getDefaultValue: () => @"..\schemas\pa-yaml\v3.0\pa.yaml-schema.json" - ); + ); schemaOption.AddValidator(result => { @@ -72,7 +72,6 @@ public static RootCommand GetRootCommand() { result.ErrorMessage = "The schema file does not exist"; } - }); // define root diff --git a/src/YAMLValidator/Program.cs b/src/YAMLValidator/Program.cs index a43d4227..46626ddf 100644 --- a/src/YAMLValidator/Program.cs +++ b/src/YAMLValidator/Program.cs @@ -3,7 +3,7 @@ using System.CommandLine; -namespace YAMLValidator; +namespace Microsoft.PowerPlatform.PowerApps.Persistence; internal sealed class Program { From 18241b3ea5bc8ce9572f0e9a56b8e6e97ec9f5c7 Mon Sep 17 00:00:00 2001 From: Amruth Baskar Date: Tue, 4 Jun 2024 15:04:17 -0700 Subject: [PATCH 03/11] change comment location --- src/YAMLValidator/InputProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YAMLValidator/InputProcessor.cs index c84b1387..86907b29 100644 --- a/src/YAMLValidator/InputProcessor.cs +++ b/src/YAMLValidator/InputProcessor.cs @@ -50,10 +50,10 @@ public static RootCommand GetRootCommand() } }); + // assume local schema file exists in nuget package, use relative filepath for now var schemaOption = new Option( name: "--schema", description: "The path to the schema json file", - // assume local schema file exists in nuget package, use relative filepath for now getDefaultValue: () => @"..\schemas\pa-yaml\v3.0\pa.yaml-schema.json" ); From 8dfa7c7935f6a9c6ade832e7f4fbbb294bafa7d6 Mon Sep 17 00:00:00 2001 From: abaskk-msft Date: Tue, 11 Jun 2024 11:45:22 -0700 Subject: [PATCH 04/11] Copy schemas to YAML Validator and update subschema references (#666) --- docs/control-property-schema.json | 2 +- docs/control-type-schema.json | 2 +- docs/pa.yaml-schema.json | 6 ++--- src/YAMLValidator/InputProcessor.cs | 2 +- src/YAMLValidator/YAMLValidator.csproj | 33 ++++++++++++++++---------- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/docs/control-property-schema.json b/docs/control-property-schema.json index 6d7b3f6b..748af747 100644 --- a/docs/control-property-schema.json +++ b/docs/control-property-schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/microsoft/PowerApps-Tooling/master/docs/control-type-schema.json", + "$id": "control-property-schema.json", "title": "Microsoft Power Apps Properties", "description": "The properties of the control", "type": "object", diff --git a/docs/control-type-schema.json b/docs/control-type-schema.json index 081e9761..2aac5d7d 100644 --- a/docs/control-type-schema.json +++ b/docs/control-type-schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/microsoft/PowerApps-Tooling/master/docs/control-type-schema.json", + "$id": "control-type-schema.json", "title": "Microsoft Power Apps Control Type", "description": "The type of the control", "type": "string", diff --git a/docs/pa.yaml-schema.json b/docs/pa.yaml-schema.json index e4878ef5..23bb5437 100644 --- a/docs/pa.yaml-schema.json +++ b/docs/pa.yaml-schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/microsoft/PowerApps-Tooling/master/docs/pa.yaml-schema.json", + "$id": "pa.yaml-schema.json", "title": "Microsoft Power Apps", "description": "Canvas YAML", "oneOf": [ @@ -23,7 +23,7 @@ "type": "object", "properties": { "Control": { - "$ref": "control-type-schema.json#" + "$ref": "subschemas/control-type-schema.json" }, "Variant": { "description": "The variant of the control", @@ -40,7 +40,7 @@ "Settings": { "type": "object" }, "Style": { "type": "string" }, "Properties": { - "$ref": "control-property-schema.json#" + "$ref": "subschemas/control-property-schema.json" }, "CustomProperties": { "type": "array" diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YAMLValidator/InputProcessor.cs index 86907b29..e3024564 100644 --- a/src/YAMLValidator/InputProcessor.cs +++ b/src/YAMLValidator/InputProcessor.cs @@ -54,7 +54,7 @@ public static RootCommand GetRootCommand() var schemaOption = new Option( name: "--schema", description: "The path to the schema json file", - getDefaultValue: () => @"..\schemas\pa-yaml\v3.0\pa.yaml-schema.json" + getDefaultValue: () => @".\schema\pa.yaml-schema.json" ); schemaOption.AddValidator(result => diff --git a/src/YAMLValidator/YAMLValidator.csproj b/src/YAMLValidator/YAMLValidator.csproj index 0dae98fa..fb992231 100644 --- a/src/YAMLValidator/YAMLValidator.csproj +++ b/src/YAMLValidator/YAMLValidator.csproj @@ -1,19 +1,26 @@ - - Exe - net8.0 - enable - enable - + + Exe + net8.0 + enable + enable + - - - - + + + + + - - - + + + + + + + + + From e7f3fd825451a518249d786fe4474cc332b88175 Mon Sep 17 00:00:00 2001 From: abaskk-msft Date: Fri, 21 Jun 2024 11:53:43 -0700 Subject: [PATCH 05/11] Yaml Validator - Iteration One (#672) basic yaml validator with unit tests for the validator --- .version/PipelineAssemblyInfo.cs | 2 +- src/PASopa.sln | 9 ++- src/YAMLValidator.Tests/ValidatorTest.cs | 46 ++++++++++++++ .../YAMLValidator.Tests.csproj | 34 +++++++++++ .../ControlWithInvalidProperty.yaml | 3 + .../_TestData/InvalidYaml/Empty.yaml | 0 .../_TestData/InvalidYaml/EmptyArray.yaml | 4 ++ .../InvalidYaml/NamelessObjectNoControl.yaml | 1 + .../InvalidYaml/ScreenWithNameNoColon.yaml | 1 + .../InvalidYaml/ScreenWithNameNoValue.yaml | 1 + .../ScreenWithoutControlProperty.yaml | 2 + .../InvalidYaml/WrongControlDefinition.yaml | 2 + .../ValidYaml/NamelessObjectWithControl.yaml | 2 + .../SimpleNoRecursiveDefinition.yaml | 2 + .../_TestData/ValidYaml/ValidScreen1.yaml | 30 ++++++++++ src/YAMLValidator/InputProcessor.cs | 40 ++++++++----- src/YAMLValidator/Orchestrator.cs | 42 +++++++++++++ src/YAMLValidator/Program.cs | 4 +- src/YAMLValidator/SchemaLoader.cs | 28 +++++++++ src/YAMLValidator/ValidationRequest.cs | 6 ++ src/YAMLValidator/Validator.cs | 60 +++++++++++++++++++ src/YAMLValidator/VerbosityData.cs | 25 ++++++++ src/YAMLValidator/YAMLValidator.csproj | 9 +++ src/YAMLValidator/YamlLoader.cs | 33 ++++++++++ src/YAMLValidator/YamlValidatorConstants.cs | 14 +++++ src/YAMLValidator/YamlValidatorError.cs | 39 ++++++++++++ src/YAMLValidator/YamlValidatorResults.cs | 19 ++++++ src/YAMLValidator/YamlValidatorUtility.cs | 22 +++++++ 28 files changed, 460 insertions(+), 20 deletions(-) create mode 100644 src/YAMLValidator.Tests/ValidatorTest.cs create mode 100644 src/YAMLValidator.Tests/YAMLValidator.Tests.csproj create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/Empty.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml create mode 100644 src/YAMLValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml create mode 100644 src/YAMLValidator/Orchestrator.cs create mode 100644 src/YAMLValidator/SchemaLoader.cs create mode 100644 src/YAMLValidator/ValidationRequest.cs create mode 100644 src/YAMLValidator/Validator.cs create mode 100644 src/YAMLValidator/VerbosityData.cs create mode 100644 src/YAMLValidator/YamlLoader.cs create mode 100644 src/YAMLValidator/YamlValidatorConstants.cs create mode 100644 src/YAMLValidator/YamlValidatorError.cs create mode 100644 src/YAMLValidator/YamlValidatorResults.cs create mode 100644 src/YAMLValidator/YamlValidatorUtility.cs diff --git a/.version/PipelineAssemblyInfo.cs b/.version/PipelineAssemblyInfo.cs index b1f2f756..f5cc4c28 100644 --- a/.version/PipelineAssemblyInfo.cs +++ b/.version/PipelineAssemblyInfo.cs @@ -5,4 +5,4 @@ using System.Reflection; [assembly: AssemblyVersion("0.0.0.0")] [assembly: AssemblyFileVersion("0.0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0.0-dev-00000000")] +[assembly: AssemblyInformationalVersion("0.0.0.0-dev-00000000")] \ No newline at end of file diff --git a/src/PASopa.sln b/src/PASopa.sln index 63347bf4..63f3f564 100644 --- a/src/PASopa.sln +++ b/src/PASopa.sln @@ -20,7 +20,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Pow EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence.Tests", "Persistence.Tests\Persistence.Tests.csproj", "{8AB1C901-FE5E-44BF-AA21-B8F20A9D7CDD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YAMLValidator", "YAMLValidator\YAMLValidator.csproj", "{F0AD11CE-E634-4945-A6B1-7866CDE0059C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YAMLValidator", "YAMLValidator\YAMLValidator.csproj", "{F0AD11CE-E634-4945-A6B1-7866CDE0059C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YAMLValidator.Tests", "YAMLValidator.Tests\YAMLValidator.Tests.csproj", "{8BA5DD4B-9423-4827-AF37-540E0300DB9A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -52,6 +54,10 @@ Global {F0AD11CE-E634-4945-A6B1-7866CDE0059C}.Debug|Any CPU.Build.0 = Debug|Any CPU {F0AD11CE-E634-4945-A6B1-7866CDE0059C}.Release|Any CPU.ActiveCfg = Release|Any CPU {F0AD11CE-E634-4945-A6B1-7866CDE0059C}.Release|Any CPU.Build.0 = Release|Any CPU + {8BA5DD4B-9423-4827-AF37-540E0300DB9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BA5DD4B-9423-4827-AF37-540E0300DB9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BA5DD4B-9423-4827-AF37-540E0300DB9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BA5DD4B-9423-4827-AF37-540E0300DB9A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -59,6 +65,7 @@ Global GlobalSection(NestedProjects) = preSolution {8AD94CC0-7330-4880-A8E0-177B37CDB27B} = {4993E606-484B-46D9-892E-7AE9CE8D4423} {8AB1C901-FE5E-44BF-AA21-B8F20A9D7CDD} = {4993E606-484B-46D9-892E-7AE9CE8D4423} + {8BA5DD4B-9423-4827-AF37-540E0300DB9A} = {4993E606-484B-46D9-892E-7AE9CE8D4423} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C936F8B1-DE7A-4401-95D5-5E199210F960} diff --git a/src/YAMLValidator.Tests/ValidatorTest.cs b/src/YAMLValidator.Tests/ValidatorTest.cs new file mode 100644 index 00000000..906bcaf4 --- /dev/null +++ b/src/YAMLValidator.Tests/ValidatorTest.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Json.Schema; +using Microsoft.PowerPlatform.PowerApps.Persistence; + +namespace YamlValidatorTests; + +[TestClass] +public class ValidatorTest +{ + private const string _validPath = @".\_TestData\ValidYaml"; + private const string _invalidPath = @".\_TestData\InvalidYaml"; + private const string _schemaPath = @"..\YAMLValidator\schema\pa.yaml-schema.json"; + + private readonly JsonSchema _schema; + private readonly Validator _yamlValidator; + + public ValidatorTest() + { + var schemaFileLoader = new SchemaLoader(); + _schema = schemaFileLoader.Load(_schemaPath); + var resultVerbosity = new VerbosityData(YamlValidatorConstants.verbose); + _yamlValidator = new Validator(resultVerbosity.EvalOptions, resultVerbosity.JsonOutputOptions); + } + + [TestMethod] + [DataRow($@"{_invalidPath}\ScreenWithNameNoColon.yaml", false)] + [DataRow($@"{_invalidPath}\ScreenWithNameNoValue.yaml", false)] + [DataRow($@"{_invalidPath}\ScreenWithoutControlProperty.yaml", false)] + [DataRow($@"{_invalidPath}\WrongControlDefinition.yaml", false)] + [DataRow($@"{_invalidPath}\ControlWithInvalidProperty.yaml", false)] + [DataRow($@"{_invalidPath}\EmptyArray.yaml", false)] + [DataRow($@"{_invalidPath}\Empty.yaml", false)] + [DataRow($@"{_invalidPath}\NamelessObjectNoControl.yaml", false)] + [DataRow($@"{_validPath}\NamelessObjectWithControl.yaml", true)] + [DataRow($@"{_validPath}\ValidScreen1.yaml", true)] + [DataRow($@"{_validPath}\SimpleNoRecursiveDefinition.yaml", true)] + + public void TestValidation(string filepath, bool expectedResult) + { + var rawYaml = YamlValidatorUtility.ReadFileData($@"{filepath}"); + var result = _yamlValidator.Validate(_schema, rawYaml); + Assert.IsTrue(result.SchemaValid == expectedResult); + } +} diff --git a/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj b/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj new file mode 100644 index 00000000..ee0eec29 --- /dev/null +++ b/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj @@ -0,0 +1,34 @@ + + + + net8.0 + enable + enable + false + true + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml new file mode 100644 index 00000000..999ea429 --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml @@ -0,0 +1,3 @@ +Screen2: + Control: Screen + InvalidProperty: "invalid" diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/Empty.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/Empty.yaml new file mode 100644 index 00000000..e69de29b diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml new file mode 100644 index 00000000..c59ec775 --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml @@ -0,0 +1,4 @@ +- +- +- +- diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml new file mode 100644 index 00000000..397db75f --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml @@ -0,0 +1 @@ +: diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml new file mode 100644 index 00000000..9daeafb9 --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml @@ -0,0 +1 @@ +test diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml new file mode 100644 index 00000000..e901b4d3 --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml @@ -0,0 +1 @@ +test: diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml new file mode 100644 index 00000000..eef6736d --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml @@ -0,0 +1,2 @@ +Screen: + ComponentName: "test" diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml b/src/YAMLValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml new file mode 100644 index 00000000..b0bf6878 --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml @@ -0,0 +1,2 @@ +TestScreen: + "abcd" diff --git a/src/YAMLValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml b/src/YAMLValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml new file mode 100644 index 00000000..b714ba34 --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml @@ -0,0 +1,2 @@ +: + Control: "bdbd" diff --git a/src/YAMLValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml b/src/YAMLValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml new file mode 100644 index 00000000..616601da --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml @@ -0,0 +1,2 @@ +LoginPage: + Control: "Button" diff --git a/src/YAMLValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml b/src/YAMLValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml new file mode 100644 index 00000000..0ed69b8a --- /dev/null +++ b/src/YAMLValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml @@ -0,0 +1,30 @@ +Screen2: + Control: Screen + Children: + - ButtonCanvas2: + Control: Button + Properties: + OnSelect: =Navigate(Screen1) + Text: ="Back" + Height: =53 + Width: =172 + X: =632 + Y: =550 + - TextCanvas1: + Control: Text + Properties: + Align: ='TextCanvas.Align'.Center + Size: =50 + Text: ="Hello" + Height: =91 + Width: =368 + X: =517 + Y: =44 + - Image1: + Control: Image + Properties: + Image: ='pexels-pixabay-417173' + Height: =361 + Width: =466 + X: =447 + Y: =135 diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YAMLValidator/InputProcessor.cs index e3024564..28f009cf 100644 --- a/src/YAMLValidator/InputProcessor.cs +++ b/src/YAMLValidator/InputProcessor.cs @@ -4,15 +4,25 @@ using System.CommandLine; namespace Microsoft.PowerPlatform.PowerApps.Persistence; -internal sealed class InputProcessor +public class InputProcessor { - public static RootCommand GetRootCommand() + + private static void ProcessFiles(string path, string schema, string pathType) { + // read only records + var filePathInfo = new ValidationRequest(path, schema, pathType); + // to do: add verbosity flag and configure this as a paramter pass after + // validation to ensure that only certain values are passed to it + var verbosityInfo = new VerbosityData(YamlValidatorConstants.verbose); - const string FileTypeName = "file"; - const string FolderTypeName = "folder"; - const string YamlFileExtension = ".yaml"; - const string JsonFileExtension = ".json"; + var validator = new Validator(verbosityInfo.EvalOptions, verbosityInfo.JsonOutputOptions); + var schemaLoader = new SchemaLoader(); + var fileLoader = new YamlLoader(); + var orchestrator = new Orchestrator(fileLoader, schemaLoader, validator); + orchestrator.RunValidation(filePathInfo); + } + public static RootCommand GetRootCommand() + { var pathOption = new Option( name: "--path", @@ -28,7 +38,8 @@ public static RootCommand GetRootCommand() var pathType = string.Empty; if (string.IsNullOrEmpty(inputFilePath)) { - result.ErrorMessage = "The input is invalid, input must be a filepath to a yaml file or a folder path to a folder of yaml files"; + result.ErrorMessage = "The input is invalid, input must be a filepath to a yaml file \\" + + "or a folder path to a folder of yaml files"; } else if (!Directory.Exists(inputFilePath) && !File.Exists(inputFilePath)) { @@ -36,14 +47,14 @@ public static RootCommand GetRootCommand() } else if (Directory.Exists(inputFilePath)) { - if (Directory.GetFiles(inputFilePath, $"*{YamlFileExtension}").Length == 0) + if (Directory.GetFiles(inputFilePath, $"*{YamlValidatorConstants.YamlFileExtension}").Length == 0) { result.ErrorMessage = "The input folder does not contain any yaml files"; } } else if (File.Exists(inputFilePath)) { - if (Path.GetExtension(inputFilePath) != YamlFileExtension) + if (Path.GetExtension(inputFilePath) != YamlValidatorConstants.YamlFileExtension) { result.ErrorMessage = "The input file must be a yaml file"; } @@ -64,7 +75,7 @@ public static RootCommand GetRootCommand() { result.ErrorMessage = "Schema option selected, but no schema was provided"; } - else if (Path.GetExtension(schemaPath) != JsonFileExtension) + else if (Path.GetExtension(schemaPath) != YamlValidatorConstants.JsonFileExtension) { result.ErrorMessage = "The schema file must be a json file"; } @@ -87,13 +98,10 @@ public static RootCommand GetRootCommand() validateCommand.SetHandler((pathOptionVal, schemaOptionVal) => { // validation has completed, we either have a file or folder - var fileType = File.Exists(pathOptionVal) ? FileTypeName : FolderTypeName; - Console.WriteLine($"ValidatingPath: {pathOptionVal}"); - Console.WriteLine($"Path type: {fileType}"); - Console.WriteLine($"Schema: {schemaOptionVal}"); + var pathType = File.Exists(pathOptionVal) ? YamlValidatorConstants.FileTypeName : + YamlValidatorConstants.FolderTypeName; + ProcessFiles(pathOptionVal, schemaOptionVal, pathType); - // to do -> add handler to validate all yaml files in a folder are actually parseable as yaml - // or add handler to validate a single yaml file is parseable as yaml }, pathOption, schemaOption); rootCommand.AddCommand(validateCommand); diff --git a/src/YAMLValidator/Orchestrator.cs b/src/YAMLValidator/Orchestrator.cs new file mode 100644 index 00000000..e31edb6e --- /dev/null +++ b/src/YAMLValidator/Orchestrator.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public class Orchestrator +{ + private readonly YamlLoader _fileLoader; + private readonly SchemaLoader _schemaLoader; + private readonly Validator _validator; + + public Orchestrator(YamlLoader fileLoader, SchemaLoader schemaLoader, Validator validator) + { + _fileLoader = fileLoader; + _schemaLoader = schemaLoader; + _validator = validator; + } + + public void RunValidation(ValidationRequest inputData) + { + var schemaPath = inputData.SchemaPath; + var path = inputData.FilePath; + var pathType = inputData.FilePathType; + + var yamlData = _fileLoader.Load(path, pathType); + var serializedSchema = _schemaLoader.Load(schemaPath); + + foreach (var yamlFileData in yamlData) + { + Console.WriteLine($"Validation for {yamlFileData.Key}"); + var result = _validator.Validate(serializedSchema, yamlFileData.Value); + Console.WriteLine($"Validation Result: {result.SchemaValid}"); + foreach (var error in result.TraversalResults) + { + Console.WriteLine($"{error}"); + } + Console.WriteLine(); + } + } + + + +} diff --git a/src/YAMLValidator/Program.cs b/src/YAMLValidator/Program.cs index 46626ddf..0a389470 100644 --- a/src/YAMLValidator/Program.cs +++ b/src/YAMLValidator/Program.cs @@ -5,9 +5,9 @@ namespace Microsoft.PowerPlatform.PowerApps.Persistence; -internal sealed class Program +public class Program { - private static void Main(String[] args) + private static void Main(string[] args) { var inputProcessor = InputProcessor.GetRootCommand(); inputProcessor.Invoke(args); diff --git a/src/YAMLValidator/SchemaLoader.cs b/src/YAMLValidator/SchemaLoader.cs new file mode 100644 index 00000000..54e0391c --- /dev/null +++ b/src/YAMLValidator/SchemaLoader.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Json.Schema; + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public class SchemaLoader +{ + private const string _schemaFolderPath = "subschemas"; + + public JsonSchema Load(string schemaPath) + { + var node = JsonSchema.FromFile(schemaPath); + var schemaFolder = Path.GetDirectoryName(schemaPath); + var subschemaPaths = Directory.GetFiles($@"{schemaFolder}\{_schemaFolderPath}", + $"*{YamlValidatorConstants.JsonFileExtension}"); + + foreach (var path in subschemaPaths) + { + var subschema = JsonSchema.FromFile(path); + SchemaRegistry.Global.Register(subschema); + } + + return node; + } + +} + diff --git a/src/YAMLValidator/ValidationRequest.cs b/src/YAMLValidator/ValidationRequest.cs new file mode 100644 index 00000000..0b46204c --- /dev/null +++ b/src/YAMLValidator/ValidationRequest.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public readonly record struct ValidationRequest(string FilePath, string SchemaPath, string FilePathType); diff --git a/src/YAMLValidator/Validator.cs b/src/YAMLValidator/Validator.cs new file mode 100644 index 00000000..27d0bcfb --- /dev/null +++ b/src/YAMLValidator/Validator.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Json.Schema; +using Yaml2JsonNode; +using System.Text.Json; +using Micorosoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence; + +public class Validator +{ + private readonly EvaluationOptions _verbosityOptions; + private readonly JsonSerializerOptions _serializerOptions; + + + public Validator(EvaluationOptions options, JsonSerializerOptions resultSerializeOptions) + { + // to do: add verbosity flag and allow users to choose verbosity of evaluation + _verbosityOptions = options; + _serializerOptions = resultSerializeOptions; + + } + + public YamlValidatorResults Validate(JsonSchema schema, string yamlFileData) + { + var yamlStream = YamlValidatorUtility.MakeYamlStream(yamlFileData); + // tbd: inquire about empty edge case handling -> error or valid? + var jsonData = yamlStream.Documents.Count > 0 ? yamlStream.Documents[0].ToJsonNode() : null; + // tbd: inquire about empty edge case handling -> error or valid? + // here we say that empty yaml is serialized as null json + if (jsonData == null) + { + return new YamlValidatorResults(false, new List { new("Empty YAML file") }); + } + var results = schema.Evaluate(jsonData, _verbosityOptions); + var output = JsonSerializer.Serialize(results, _serializerOptions); + + // TBD: remove, placeholder to view output for debugging + Console.WriteLine(output); + + var schemaValidity = results.IsValid; + // TBD: filter actual errors versus false positives + // we look for errors that are not valid, have errors, and have an instance location (i.e are not oneOf errors) + var yamlValidatorErrors = new List(); + if (!schemaValidity) + { + IReadOnlyList traceList = results.Details.Where( + node => !node.IsValid && + node.HasErrors).ToList(); + foreach (var trace in traceList) + { + yamlValidatorErrors.Add(new YamlValidatorError(trace)); + } + } + IReadOnlyList fileErrors = yamlValidatorErrors; + var finalResults = new YamlValidatorResults(results.IsValid, fileErrors); + return finalResults; + + } +} diff --git a/src/YAMLValidator/VerbosityData.cs b/src/YAMLValidator/VerbosityData.cs new file mode 100644 index 00000000..06a7c638 --- /dev/null +++ b/src/YAMLValidator/VerbosityData.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using System.Text.Json; +using Json.Schema; + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public readonly record struct VerbosityData +{ + public EvaluationOptions EvalOptions { get; } + public JsonSerializerOptions JsonOutputOptions { get; } + + public VerbosityData(string verbosityLevel) + { + EvalOptions = new EvaluationOptions(); + JsonOutputOptions = new JsonSerializerOptions { Converters = { new EvaluationResultsJsonConverter() } }; + + if (verbosityLevel == YamlValidatorConstants.verbose) + { + EvalOptions.OutputFormat = OutputFormat.List; + return; + } + EvalOptions.OutputFormat = OutputFormat.Flag; + } +} + diff --git a/src/YAMLValidator/YAMLValidator.csproj b/src/YAMLValidator/YAMLValidator.csproj index fb992231..549b1d63 100644 --- a/src/YAMLValidator/YAMLValidator.csproj +++ b/src/YAMLValidator/YAMLValidator.csproj @@ -7,10 +7,19 @@ enable + + 1591, CA1822 + + + + 1591, CA1822 + + + diff --git a/src/YAMLValidator/YamlLoader.cs b/src/YAMLValidator/YamlLoader.cs new file mode 100644 index 00000000..9a8e2a82 --- /dev/null +++ b/src/YAMLValidator/YamlLoader.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.ObjectModel; + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public class YamlLoader +{ + + public IReadOnlyDictionary Load(string filePath, string pathType) + { + var deserializedYaml = new Dictionary(); + if (pathType == YamlValidatorConstants.FileTypeName) + { + var fileName = Path.GetFileName(filePath); + var yamlText = YamlValidatorUtility.ReadFileData(filePath); + deserializedYaml.Add(fileName, yamlText); + return new ReadOnlyDictionary(deserializedYaml); + } + + // to do: address edge case of .yml files + var files = Directory.GetFiles(filePath, $"*{YamlValidatorConstants.YamlFileExtension}"); + foreach (var file in files) + { + var fileName = Path.GetFileName(file); + var yamlText = YamlValidatorUtility.ReadFileData(file); + deserializedYaml.Add(fileName, yamlText); + } + + return new ReadOnlyDictionary(deserializedYaml); + } + +} diff --git a/src/YAMLValidator/YamlValidatorConstants.cs b/src/YAMLValidator/YamlValidatorConstants.cs new file mode 100644 index 00000000..dcab1e24 --- /dev/null +++ b/src/YAMLValidator/YamlValidatorConstants.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public class YamlValidatorConstants +{ + public const string FileTypeName = "file"; + public const string FolderTypeName = "folder"; + public const string YamlFileExtension = ".yaml"; + public const string YmlFileExtension = ".yml"; + public const string JsonFileExtension = ".json"; + + public const string verbose = "verbose"; +} diff --git a/src/YAMLValidator/YamlValidatorError.cs b/src/YAMLValidator/YamlValidatorError.cs new file mode 100644 index 00000000..f8b62003 --- /dev/null +++ b/src/YAMLValidator/YamlValidatorError.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Json.Schema; + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public class YamlValidatorError +{ + public string InstanceLocation { get; } + public string SchemaPath { get; } + public IReadOnlyDictionary? Errors { get; } + + public YamlValidatorError(EvaluationResults results) + { + InstanceLocation = results.InstanceLocation.ToString(); + SchemaPath = results.EvaluationPath.ToString(); + Errors = results.Errors; + } + public YamlValidatorError(string error) + { + InstanceLocation = ""; + SchemaPath = ""; + Errors = new Dictionary { { "", error } }; + } + + public override string ToString() + { + var errString = ""; + if (Errors != null) + { + foreach (var error in Errors) + { + var errType = string.IsNullOrEmpty(error.Key) ? "Error" : error.Key; + errString += $"\t{errType}: {error.Value}\n"; + } + } + return $"InstanceLocation: {InstanceLocation}\nSchemaPath: {SchemaPath}\nErrors:\n{errString}"; + } +} diff --git a/src/YAMLValidator/YamlValidatorResults.cs b/src/YAMLValidator/YamlValidatorResults.cs new file mode 100644 index 00000000..9b9b4ea8 --- /dev/null +++ b/src/YAMLValidator/YamlValidatorResults.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +using Microsoft.PowerPlatform.PowerApps.Persistence; + +namespace Micorosoft.PowerPlatform.PowerApps.Persistence; +public class YamlValidatorResults +{ + public bool SchemaValid { get; } + public IReadOnlyList TraversalResults { get; } + + public YamlValidatorResults(bool schemaValid, IReadOnlyList traversalResults) + { + SchemaValid = schemaValid; + TraversalResults = traversalResults; + + } +} diff --git a/src/YAMLValidator/YamlValidatorUtility.cs b/src/YAMLValidator/YamlValidatorUtility.cs new file mode 100644 index 00000000..4e9829c2 --- /dev/null +++ b/src/YAMLValidator/YamlValidatorUtility.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// using YamlDotNet.Core; +using YamlDotNet.RepresentationModel; + +namespace Microsoft.PowerPlatform.PowerApps.Persistence; +public class YamlValidatorUtility +{ + public static string ReadFileData(string filePath) + { + var yamlData = File.ReadAllText(filePath); + return yamlData; + } + + public static YamlStream MakeYamlStream(string yamlString) + { + var stream = new YamlStream(); + stream.Load(new StringReader(yamlString)); + return stream; + } +} From be973a9c107b030d96cd42d1b74aad51daa5092c Mon Sep 17 00:00:00 2001 From: Amruth Baskar Date: Mon, 24 Jun 2024 14:59:24 -0700 Subject: [PATCH 06/11] change name of project and nest namespace in persistence (..Persitence.YamlValidator), do same for test --- src/PASopa.sln | 4 ++-- src/YAMLValidator.Tests/ValidatorTest.cs | 8 ++++---- .../YAMLValidator.Tests.csproj | 2 +- ...YamlValidatorConstants.cs => Constants.cs} | 4 ++-- src/YAMLValidator/InputProcessor.cs | 14 +++++++------- src/YAMLValidator/Orchestrator.cs | 2 +- src/YAMLValidator/Program.cs | 2 +- src/YAMLValidator/SchemaLoader.cs | 4 ++-- .../{YamlValidatorUtility.cs => Utility.cs} | 4 ++-- src/YAMLValidator/ValidationRequest.cs | 2 +- src/YAMLValidator/Validator.cs | 18 +++++++++--------- ...amlValidatorError.cs => ValidatorError.cs} | 8 ++++---- src/YAMLValidator/ValidatorResults.cs | 16 ++++++++++++++++ src/YAMLValidator/VerbosityData.cs | 4 ++-- src/YAMLValidator/YamlLoader.cs | 10 +++++----- src/YAMLValidator/YamlValidatorResults.cs | 19 ------------------- 16 files changed, 59 insertions(+), 62 deletions(-) rename src/YAMLValidator/{YamlValidatorConstants.cs => Constants.cs} (80%) rename src/YAMLValidator/{YamlValidatorUtility.cs => Utility.cs} (83%) rename src/YAMLValidator/{YamlValidatorError.cs => ValidatorError.cs} (83%) create mode 100644 src/YAMLValidator/ValidatorResults.cs delete mode 100644 src/YAMLValidator/YamlValidatorResults.cs diff --git a/src/PASopa.sln b/src/PASopa.sln index 63f3f564..77f0ce50 100644 --- a/src/PASopa.sln +++ b/src/PASopa.sln @@ -20,9 +20,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Pow EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence.Tests", "Persistence.Tests\Persistence.Tests.csproj", "{8AB1C901-FE5E-44BF-AA21-B8F20A9D7CDD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YAMLValidator", "YAMLValidator\YAMLValidator.csproj", "{F0AD11CE-E634-4945-A6B1-7866CDE0059C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YamlValidator", "YAMLValidator\YamlValidator.csproj", "{F0AD11CE-E634-4945-A6B1-7866CDE0059C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YAMLValidator.Tests", "YAMLValidator.Tests\YAMLValidator.Tests.csproj", "{8BA5DD4B-9423-4827-AF37-540E0300DB9A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YamlValidator.Tests", "YAMLValidator.Tests\YamlValidator.Tests.csproj", "{8BA5DD4B-9423-4827-AF37-540E0300DB9A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/YAMLValidator.Tests/ValidatorTest.cs b/src/YAMLValidator.Tests/ValidatorTest.cs index 906bcaf4..4523aeee 100644 --- a/src/YAMLValidator.Tests/ValidatorTest.cs +++ b/src/YAMLValidator.Tests/ValidatorTest.cs @@ -2,9 +2,9 @@ // Licensed under the MIT License. using Json.Schema; -using Microsoft.PowerPlatform.PowerApps.Persistence; +using Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; -namespace YamlValidatorTests; +namespace Persistence.Tests.YamlValidator; [TestClass] public class ValidatorTest @@ -20,7 +20,7 @@ public ValidatorTest() { var schemaFileLoader = new SchemaLoader(); _schema = schemaFileLoader.Load(_schemaPath); - var resultVerbosity = new VerbosityData(YamlValidatorConstants.verbose); + var resultVerbosity = new VerbosityData(Constants.verbose); _yamlValidator = new Validator(resultVerbosity.EvalOptions, resultVerbosity.JsonOutputOptions); } @@ -39,7 +39,7 @@ public ValidatorTest() public void TestValidation(string filepath, bool expectedResult) { - var rawYaml = YamlValidatorUtility.ReadFileData($@"{filepath}"); + var rawYaml = Utility.ReadFileData($@"{filepath}"); var result = _yamlValidator.Validate(_schema, rawYaml); Assert.IsTrue(result.SchemaValid == expectedResult); } diff --git a/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj b/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj index ee0eec29..d77e2bc4 100644 --- a/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj +++ b/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/YAMLValidator/YamlValidatorConstants.cs b/src/YAMLValidator/Constants.cs similarity index 80% rename from src/YAMLValidator/YamlValidatorConstants.cs rename to src/YAMLValidator/Constants.cs index dcab1e24..5c0722ca 100644 --- a/src/YAMLValidator/YamlValidatorConstants.cs +++ b/src/YAMLValidator/Constants.cs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.PowerPlatform.PowerApps.Persistence; -public class YamlValidatorConstants +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; +public class Constants { public const string FileTypeName = "file"; public const string FolderTypeName = "folder"; diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YAMLValidator/InputProcessor.cs index 28f009cf..2eefffaf 100644 --- a/src/YAMLValidator/InputProcessor.cs +++ b/src/YAMLValidator/InputProcessor.cs @@ -3,7 +3,7 @@ using System.CommandLine; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class InputProcessor { @@ -13,7 +13,7 @@ private static void ProcessFiles(string path, string schema, string pathType) var filePathInfo = new ValidationRequest(path, schema, pathType); // to do: add verbosity flag and configure this as a paramter pass after // validation to ensure that only certain values are passed to it - var verbosityInfo = new VerbosityData(YamlValidatorConstants.verbose); + var verbosityInfo = new VerbosityData(Constants.verbose); var validator = new Validator(verbosityInfo.EvalOptions, verbosityInfo.JsonOutputOptions); var schemaLoader = new SchemaLoader(); @@ -47,14 +47,14 @@ public static RootCommand GetRootCommand() } else if (Directory.Exists(inputFilePath)) { - if (Directory.GetFiles(inputFilePath, $"*{YamlValidatorConstants.YamlFileExtension}").Length == 0) + if (Directory.GetFiles(inputFilePath, $"*{Constants.YamlFileExtension}").Length == 0) { result.ErrorMessage = "The input folder does not contain any yaml files"; } } else if (File.Exists(inputFilePath)) { - if (Path.GetExtension(inputFilePath) != YamlValidatorConstants.YamlFileExtension) + if (Path.GetExtension(inputFilePath) != Constants.YamlFileExtension) { result.ErrorMessage = "The input file must be a yaml file"; } @@ -75,7 +75,7 @@ public static RootCommand GetRootCommand() { result.ErrorMessage = "Schema option selected, but no schema was provided"; } - else if (Path.GetExtension(schemaPath) != YamlValidatorConstants.JsonFileExtension) + else if (Path.GetExtension(schemaPath) != Constants.JsonFileExtension) { result.ErrorMessage = "The schema file must be a json file"; } @@ -98,8 +98,8 @@ public static RootCommand GetRootCommand() validateCommand.SetHandler((pathOptionVal, schemaOptionVal) => { // validation has completed, we either have a file or folder - var pathType = File.Exists(pathOptionVal) ? YamlValidatorConstants.FileTypeName : - YamlValidatorConstants.FolderTypeName; + var pathType = File.Exists(pathOptionVal) ? Constants.FileTypeName : + Constants.FolderTypeName; ProcessFiles(pathOptionVal, schemaOptionVal, pathType); }, pathOption, schemaOption); diff --git a/src/YAMLValidator/Orchestrator.cs b/src/YAMLValidator/Orchestrator.cs index e31edb6e..71d04971 100644 --- a/src/YAMLValidator/Orchestrator.cs +++ b/src/YAMLValidator/Orchestrator.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class Orchestrator { private readonly YamlLoader _fileLoader; diff --git a/src/YAMLValidator/Program.cs b/src/YAMLValidator/Program.cs index 0a389470..c35c35d9 100644 --- a/src/YAMLValidator/Program.cs +++ b/src/YAMLValidator/Program.cs @@ -3,7 +3,7 @@ using System.CommandLine; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class Program { diff --git a/src/YAMLValidator/SchemaLoader.cs b/src/YAMLValidator/SchemaLoader.cs index 54e0391c..edce53c7 100644 --- a/src/YAMLValidator/SchemaLoader.cs +++ b/src/YAMLValidator/SchemaLoader.cs @@ -3,7 +3,7 @@ using Json.Schema; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class SchemaLoader { private const string _schemaFolderPath = "subschemas"; @@ -13,7 +13,7 @@ public JsonSchema Load(string schemaPath) var node = JsonSchema.FromFile(schemaPath); var schemaFolder = Path.GetDirectoryName(schemaPath); var subschemaPaths = Directory.GetFiles($@"{schemaFolder}\{_schemaFolderPath}", - $"*{YamlValidatorConstants.JsonFileExtension}"); + $"*{Constants.JsonFileExtension}"); foreach (var path in subschemaPaths) { diff --git a/src/YAMLValidator/YamlValidatorUtility.cs b/src/YAMLValidator/Utility.cs similarity index 83% rename from src/YAMLValidator/YamlValidatorUtility.cs rename to src/YAMLValidator/Utility.cs index 4e9829c2..30d15d98 100644 --- a/src/YAMLValidator/YamlValidatorUtility.cs +++ b/src/YAMLValidator/Utility.cs @@ -4,8 +4,8 @@ // using YamlDotNet.Core; using YamlDotNet.RepresentationModel; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; -public class YamlValidatorUtility +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; +public class Utility { public static string ReadFileData(string filePath) { diff --git a/src/YAMLValidator/ValidationRequest.cs b/src/YAMLValidator/ValidationRequest.cs index 0b46204c..2182f66f 100644 --- a/src/YAMLValidator/ValidationRequest.cs +++ b/src/YAMLValidator/ValidationRequest.cs @@ -2,5 +2,5 @@ // Licensed under the MIT License. -namespace Microsoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public readonly record struct ValidationRequest(string FilePath, string SchemaPath, string FilePathType); diff --git a/src/YAMLValidator/Validator.cs b/src/YAMLValidator/Validator.cs index 27d0bcfb..2273a590 100644 --- a/src/YAMLValidator/Validator.cs +++ b/src/YAMLValidator/Validator.cs @@ -4,8 +4,8 @@ using Json.Schema; using Yaml2JsonNode; using System.Text.Json; -using Micorosoft.PowerPlatform.PowerApps.Persistence; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; + +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class Validator { @@ -21,16 +21,16 @@ public Validator(EvaluationOptions options, JsonSerializerOptions resultSerializ } - public YamlValidatorResults Validate(JsonSchema schema, string yamlFileData) + public ValidatorResults Validate(JsonSchema schema, string yamlFileData) { - var yamlStream = YamlValidatorUtility.MakeYamlStream(yamlFileData); + var yamlStream = Utility.MakeYamlStream(yamlFileData); // tbd: inquire about empty edge case handling -> error or valid? var jsonData = yamlStream.Documents.Count > 0 ? yamlStream.Documents[0].ToJsonNode() : null; // tbd: inquire about empty edge case handling -> error or valid? // here we say that empty yaml is serialized as null json if (jsonData == null) { - return new YamlValidatorResults(false, new List { new("Empty YAML file") }); + return new ValidatorResults(false, new List { new("Empty YAML file") }); } var results = schema.Evaluate(jsonData, _verbosityOptions); var output = JsonSerializer.Serialize(results, _serializerOptions); @@ -41,7 +41,7 @@ public YamlValidatorResults Validate(JsonSchema schema, string yamlFileData) var schemaValidity = results.IsValid; // TBD: filter actual errors versus false positives // we look for errors that are not valid, have errors, and have an instance location (i.e are not oneOf errors) - var yamlValidatorErrors = new List(); + var yamlValidatorErrors = new List(); if (!schemaValidity) { IReadOnlyList traceList = results.Details.Where( @@ -49,11 +49,11 @@ public YamlValidatorResults Validate(JsonSchema schema, string yamlFileData) node.HasErrors).ToList(); foreach (var trace in traceList) { - yamlValidatorErrors.Add(new YamlValidatorError(trace)); + yamlValidatorErrors.Add(new ValidatorError(trace)); } } - IReadOnlyList fileErrors = yamlValidatorErrors; - var finalResults = new YamlValidatorResults(results.IsValid, fileErrors); + IReadOnlyList fileErrors = yamlValidatorErrors; + var finalResults = new ValidatorResults(results.IsValid, fileErrors); return finalResults; } diff --git a/src/YAMLValidator/YamlValidatorError.cs b/src/YAMLValidator/ValidatorError.cs similarity index 83% rename from src/YAMLValidator/YamlValidatorError.cs rename to src/YAMLValidator/ValidatorError.cs index f8b62003..3afec499 100644 --- a/src/YAMLValidator/YamlValidatorError.cs +++ b/src/YAMLValidator/ValidatorError.cs @@ -3,20 +3,20 @@ using Json.Schema; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; -public class YamlValidatorError +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; +public class ValidatorError { public string InstanceLocation { get; } public string SchemaPath { get; } public IReadOnlyDictionary? Errors { get; } - public YamlValidatorError(EvaluationResults results) + public ValidatorError(EvaluationResults results) { InstanceLocation = results.InstanceLocation.ToString(); SchemaPath = results.EvaluationPath.ToString(); Errors = results.Errors; } - public YamlValidatorError(string error) + public ValidatorError(string error) { InstanceLocation = ""; SchemaPath = ""; diff --git a/src/YAMLValidator/ValidatorResults.cs b/src/YAMLValidator/ValidatorResults.cs new file mode 100644 index 00000000..400e7a52 --- /dev/null +++ b/src/YAMLValidator/ValidatorResults.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; +public class ValidatorResults +{ + public bool SchemaValid { get; } + public IReadOnlyList TraversalResults { get; } + + public ValidatorResults(bool schemaValid, IReadOnlyList traversalResults) + { + SchemaValid = schemaValid; + TraversalResults = traversalResults; + + } +} diff --git a/src/YAMLValidator/VerbosityData.cs b/src/YAMLValidator/VerbosityData.cs index 06a7c638..6b6efcee 100644 --- a/src/YAMLValidator/VerbosityData.cs +++ b/src/YAMLValidator/VerbosityData.cs @@ -3,7 +3,7 @@ using System.Text.Json; using Json.Schema; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public readonly record struct VerbosityData { public EvaluationOptions EvalOptions { get; } @@ -14,7 +14,7 @@ public VerbosityData(string verbosityLevel) EvalOptions = new EvaluationOptions(); JsonOutputOptions = new JsonSerializerOptions { Converters = { new EvaluationResultsJsonConverter() } }; - if (verbosityLevel == YamlValidatorConstants.verbose) + if (verbosityLevel == Constants.verbose) { EvalOptions.OutputFormat = OutputFormat.List; return; diff --git a/src/YAMLValidator/YamlLoader.cs b/src/YAMLValidator/YamlLoader.cs index 9a8e2a82..500da4d7 100644 --- a/src/YAMLValidator/YamlLoader.cs +++ b/src/YAMLValidator/YamlLoader.cs @@ -3,27 +3,27 @@ using System.Collections.ObjectModel; -namespace Microsoft.PowerPlatform.PowerApps.Persistence; +namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class YamlLoader { public IReadOnlyDictionary Load(string filePath, string pathType) { var deserializedYaml = new Dictionary(); - if (pathType == YamlValidatorConstants.FileTypeName) + if (pathType == Constants.FileTypeName) { var fileName = Path.GetFileName(filePath); - var yamlText = YamlValidatorUtility.ReadFileData(filePath); + var yamlText = Utility.ReadFileData(filePath); deserializedYaml.Add(fileName, yamlText); return new ReadOnlyDictionary(deserializedYaml); } // to do: address edge case of .yml files - var files = Directory.GetFiles(filePath, $"*{YamlValidatorConstants.YamlFileExtension}"); + var files = Directory.GetFiles(filePath, $"*{Constants.YamlFileExtension}"); foreach (var file in files) { var fileName = Path.GetFileName(file); - var yamlText = YamlValidatorUtility.ReadFileData(file); + var yamlText = Utility.ReadFileData(file); deserializedYaml.Add(fileName, yamlText); } diff --git a/src/YAMLValidator/YamlValidatorResults.cs b/src/YAMLValidator/YamlValidatorResults.cs deleted file mode 100644 index 9b9b4ea8..00000000 --- a/src/YAMLValidator/YamlValidatorResults.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - - -using Microsoft.PowerPlatform.PowerApps.Persistence; - -namespace Micorosoft.PowerPlatform.PowerApps.Persistence; -public class YamlValidatorResults -{ - public bool SchemaValid { get; } - public IReadOnlyList TraversalResults { get; } - - public YamlValidatorResults(bool schemaValid, IReadOnlyList traversalResults) - { - SchemaValid = schemaValid; - TraversalResults = traversalResults; - - } -} From ec5507e73e87efafe80dbbca6a721a20ae0da5b5 Mon Sep 17 00:00:00 2001 From: Amruth Baskar Date: Tue, 25 Jun 2024 09:15:56 -0700 Subject: [PATCH 07/11] fix code based on suggestions --- src/YAMLValidator/Constants.cs | 2 +- src/YAMLValidator/InputProcessor.cs | 4 +--- src/YAMLValidator/Utility.cs | 1 - src/YAMLValidator/ValidationRequest.cs | 1 - src/YAMLValidator/Validator.cs | 6 +----- src/YAMLValidator/VerbosityData.cs | 2 +- src/YAMLValidator/YAMLValidator.csproj | 4 +++- 7 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/YAMLValidator/Constants.cs b/src/YAMLValidator/Constants.cs index 5c0722ca..e377efd7 100644 --- a/src/YAMLValidator/Constants.cs +++ b/src/YAMLValidator/Constants.cs @@ -10,5 +10,5 @@ public class Constants public const string YmlFileExtension = ".yml"; public const string JsonFileExtension = ".json"; - public const string verbose = "verbose"; + public const string Verbose = "verbose"; } diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YAMLValidator/InputProcessor.cs index 2eefffaf..bd712d1a 100644 --- a/src/YAMLValidator/InputProcessor.cs +++ b/src/YAMLValidator/InputProcessor.cs @@ -11,9 +11,7 @@ private static void ProcessFiles(string path, string schema, string pathType) { // read only records var filePathInfo = new ValidationRequest(path, schema, pathType); - // to do: add verbosity flag and configure this as a paramter pass after - // validation to ensure that only certain values are passed to it - var verbosityInfo = new VerbosityData(Constants.verbose); + var verbosityInfo = new VerbosityData(Constants.Verbose); var validator = new Validator(verbosityInfo.EvalOptions, verbosityInfo.JsonOutputOptions); var schemaLoader = new SchemaLoader(); diff --git a/src/YAMLValidator/Utility.cs b/src/YAMLValidator/Utility.cs index 30d15d98..c3ab709a 100644 --- a/src/YAMLValidator/Utility.cs +++ b/src/YAMLValidator/Utility.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -// using YamlDotNet.Core; using YamlDotNet.RepresentationModel; namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; diff --git a/src/YAMLValidator/ValidationRequest.cs b/src/YAMLValidator/ValidationRequest.cs index 2182f66f..46199731 100644 --- a/src/YAMLValidator/ValidationRequest.cs +++ b/src/YAMLValidator/ValidationRequest.cs @@ -1,6 +1,5 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. - namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public readonly record struct ValidationRequest(string FilePath, string SchemaPath, string FilePathType); diff --git a/src/YAMLValidator/Validator.cs b/src/YAMLValidator/Validator.cs index 2273a590..cb03262e 100644 --- a/src/YAMLValidator/Validator.cs +++ b/src/YAMLValidator/Validator.cs @@ -24,9 +24,8 @@ public Validator(EvaluationOptions options, JsonSerializerOptions resultSerializ public ValidatorResults Validate(JsonSchema schema, string yamlFileData) { var yamlStream = Utility.MakeYamlStream(yamlFileData); - // tbd: inquire about empty edge case handling -> error or valid? var jsonData = yamlStream.Documents.Count > 0 ? yamlStream.Documents[0].ToJsonNode() : null; - // tbd: inquire about empty edge case handling -> error or valid? + // here we say that empty yaml is serialized as null json if (jsonData == null) { @@ -35,9 +34,6 @@ public ValidatorResults Validate(JsonSchema schema, string yamlFileData) var results = schema.Evaluate(jsonData, _verbosityOptions); var output = JsonSerializer.Serialize(results, _serializerOptions); - // TBD: remove, placeholder to view output for debugging - Console.WriteLine(output); - var schemaValidity = results.IsValid; // TBD: filter actual errors versus false positives // we look for errors that are not valid, have errors, and have an instance location (i.e are not oneOf errors) diff --git a/src/YAMLValidator/VerbosityData.cs b/src/YAMLValidator/VerbosityData.cs index 6b6efcee..d8383614 100644 --- a/src/YAMLValidator/VerbosityData.cs +++ b/src/YAMLValidator/VerbosityData.cs @@ -14,7 +14,7 @@ public VerbosityData(string verbosityLevel) EvalOptions = new EvaluationOptions(); JsonOutputOptions = new JsonSerializerOptions { Converters = { new EvaluationResultsJsonConverter() } }; - if (verbosityLevel == Constants.verbose) + if (verbosityLevel == Constants.Verbose) { EvalOptions.OutputFormat = OutputFormat.List; return; diff --git a/src/YAMLValidator/YAMLValidator.csproj b/src/YAMLValidator/YAMLValidator.csproj index bb64b624..e6653634 100644 --- a/src/YAMLValidator/YAMLValidator.csproj +++ b/src/YAMLValidator/YAMLValidator.csproj @@ -6,7 +6,9 @@ enable enable - + + + 1591, CA1822 From a75132a7deac91004b4daa3605aa0a898fcc3378 Mon Sep 17 00:00:00 2001 From: Amruth Baskar Date: Tue, 25 Jun 2024 09:19:42 -0700 Subject: [PATCH 08/11] fix test that cause ci to fail --- src/YAMLValidator.Tests/ValidatorTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/YAMLValidator.Tests/ValidatorTest.cs b/src/YAMLValidator.Tests/ValidatorTest.cs index 4523aeee..b4062d93 100644 --- a/src/YAMLValidator.Tests/ValidatorTest.cs +++ b/src/YAMLValidator.Tests/ValidatorTest.cs @@ -20,7 +20,7 @@ public ValidatorTest() { var schemaFileLoader = new SchemaLoader(); _schema = schemaFileLoader.Load(_schemaPath); - var resultVerbosity = new VerbosityData(Constants.verbose); + var resultVerbosity = new VerbosityData(Constants.Verbose); _yamlValidator = new Validator(resultVerbosity.EvalOptions, resultVerbosity.JsonOutputOptions); } From b6f062281d94d7eeacbfdc6c85454df46f8ccbe5 Mon Sep 17 00:00:00 2001 From: abaskk-msft Date: Tue, 25 Jun 2024 16:50:44 +0000 Subject: [PATCH 09/11] change project/directory name --- .../ValidatorTest.cs | 2 +- .../YamlValidator.Tests.csproj} | 0 .../_TestData/InvalidYaml/ControlWithInvalidProperty.yaml | 0 .../_TestData/InvalidYaml/Empty.yaml | 0 .../_TestData/InvalidYaml/EmptyArray.yaml | 0 .../_TestData/InvalidYaml/NamelessObjectNoControl.yaml | 0 .../_TestData/InvalidYaml/ScreenWithNameNoColon.yaml | 0 .../_TestData/InvalidYaml/ScreenWithNameNoValue.yaml | 0 .../_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml | 0 .../_TestData/InvalidYaml/WrongControlDefinition.yaml | 0 .../_TestData/ValidYaml/NamelessObjectWithControl.yaml | 0 .../_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml | 0 .../_TestData/ValidYaml/ValidScreen1.yaml | 0 src/{YAMLValidator => YamlValidator}/Constants.cs | 0 src/{YAMLValidator => YamlValidator}/InputProcessor.cs | 0 src/{YAMLValidator => YamlValidator}/Orchestrator.cs | 0 src/{YAMLValidator => YamlValidator}/Program.cs | 0 src/{YAMLValidator => YamlValidator}/SchemaLoader.cs | 0 src/{YAMLValidator => YamlValidator}/Utility.cs | 0 src/{YAMLValidator => YamlValidator}/ValidationRequest.cs | 0 src/{YAMLValidator => YamlValidator}/Validator.cs | 0 src/{YAMLValidator => YamlValidator}/ValidatorError.cs | 0 src/{YAMLValidator => YamlValidator}/ValidatorResults.cs | 0 src/{YAMLValidator => YamlValidator}/VerbosityData.cs | 0 src/{YAMLValidator => YamlValidator}/YamlLoader.cs | 0 .../YAMLValidator.csproj => YamlValidator/YamlValidator.csproj} | 0 26 files changed, 1 insertion(+), 1 deletion(-) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/ValidatorTest.cs (96%) rename src/{YAMLValidator.Tests/YAMLValidator.Tests.csproj => YamlValidator.Tests/YamlValidator.Tests.csproj} (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/Empty.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/EmptyArray.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/NamelessObjectNoControl.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/InvalidYaml/WrongControlDefinition.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/ValidYaml/NamelessObjectWithControl.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml (100%) rename src/{YAMLValidator.Tests => YamlValidator.Tests}/_TestData/ValidYaml/ValidScreen1.yaml (100%) rename src/{YAMLValidator => YamlValidator}/Constants.cs (100%) rename src/{YAMLValidator => YamlValidator}/InputProcessor.cs (100%) rename src/{YAMLValidator => YamlValidator}/Orchestrator.cs (100%) rename src/{YAMLValidator => YamlValidator}/Program.cs (100%) rename src/{YAMLValidator => YamlValidator}/SchemaLoader.cs (100%) rename src/{YAMLValidator => YamlValidator}/Utility.cs (100%) rename src/{YAMLValidator => YamlValidator}/ValidationRequest.cs (100%) rename src/{YAMLValidator => YamlValidator}/Validator.cs (100%) rename src/{YAMLValidator => YamlValidator}/ValidatorError.cs (100%) rename src/{YAMLValidator => YamlValidator}/ValidatorResults.cs (100%) rename src/{YAMLValidator => YamlValidator}/VerbosityData.cs (100%) rename src/{YAMLValidator => YamlValidator}/YamlLoader.cs (100%) rename src/{YAMLValidator/YAMLValidator.csproj => YamlValidator/YamlValidator.csproj} (100%) diff --git a/src/YAMLValidator.Tests/ValidatorTest.cs b/src/YamlValidator.Tests/ValidatorTest.cs similarity index 96% rename from src/YAMLValidator.Tests/ValidatorTest.cs rename to src/YamlValidator.Tests/ValidatorTest.cs index b4062d93..3408da83 100644 --- a/src/YAMLValidator.Tests/ValidatorTest.cs +++ b/src/YamlValidator.Tests/ValidatorTest.cs @@ -11,7 +11,7 @@ public class ValidatorTest { private const string _validPath = @".\_TestData\ValidYaml"; private const string _invalidPath = @".\_TestData\InvalidYaml"; - private const string _schemaPath = @"..\YAMLValidator\schema\pa.yaml-schema.json"; + private const string _schemaPath = @"..\YamlValidator\schema\pa.yaml-schema.json"; private readonly JsonSchema _schema; private readonly Validator _yamlValidator; diff --git a/src/YAMLValidator.Tests/YAMLValidator.Tests.csproj b/src/YamlValidator.Tests/YamlValidator.Tests.csproj similarity index 100% rename from src/YAMLValidator.Tests/YAMLValidator.Tests.csproj rename to src/YamlValidator.Tests/YamlValidator.Tests.csproj diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/ControlWithInvalidProperty.yaml diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/Empty.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/Empty.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/Empty.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/Empty.yaml diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/EmptyArray.yaml diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/NamelessObjectNoControl.yaml diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoColon.yaml diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/ScreenWithNameNoValue.yaml diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/ScreenWithoutControlProperty.yaml diff --git a/src/YAMLValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml b/src/YamlValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml rename to src/YamlValidator.Tests/_TestData/InvalidYaml/WrongControlDefinition.yaml diff --git a/src/YAMLValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml b/src/YamlValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml rename to src/YamlValidator.Tests/_TestData/ValidYaml/NamelessObjectWithControl.yaml diff --git a/src/YAMLValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml b/src/YamlValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml rename to src/YamlValidator.Tests/_TestData/ValidYaml/SimpleNoRecursiveDefinition.yaml diff --git a/src/YAMLValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml b/src/YamlValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml similarity index 100% rename from src/YAMLValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml rename to src/YamlValidator.Tests/_TestData/ValidYaml/ValidScreen1.yaml diff --git a/src/YAMLValidator/Constants.cs b/src/YamlValidator/Constants.cs similarity index 100% rename from src/YAMLValidator/Constants.cs rename to src/YamlValidator/Constants.cs diff --git a/src/YAMLValidator/InputProcessor.cs b/src/YamlValidator/InputProcessor.cs similarity index 100% rename from src/YAMLValidator/InputProcessor.cs rename to src/YamlValidator/InputProcessor.cs diff --git a/src/YAMLValidator/Orchestrator.cs b/src/YamlValidator/Orchestrator.cs similarity index 100% rename from src/YAMLValidator/Orchestrator.cs rename to src/YamlValidator/Orchestrator.cs diff --git a/src/YAMLValidator/Program.cs b/src/YamlValidator/Program.cs similarity index 100% rename from src/YAMLValidator/Program.cs rename to src/YamlValidator/Program.cs diff --git a/src/YAMLValidator/SchemaLoader.cs b/src/YamlValidator/SchemaLoader.cs similarity index 100% rename from src/YAMLValidator/SchemaLoader.cs rename to src/YamlValidator/SchemaLoader.cs diff --git a/src/YAMLValidator/Utility.cs b/src/YamlValidator/Utility.cs similarity index 100% rename from src/YAMLValidator/Utility.cs rename to src/YamlValidator/Utility.cs diff --git a/src/YAMLValidator/ValidationRequest.cs b/src/YamlValidator/ValidationRequest.cs similarity index 100% rename from src/YAMLValidator/ValidationRequest.cs rename to src/YamlValidator/ValidationRequest.cs diff --git a/src/YAMLValidator/Validator.cs b/src/YamlValidator/Validator.cs similarity index 100% rename from src/YAMLValidator/Validator.cs rename to src/YamlValidator/Validator.cs diff --git a/src/YAMLValidator/ValidatorError.cs b/src/YamlValidator/ValidatorError.cs similarity index 100% rename from src/YAMLValidator/ValidatorError.cs rename to src/YamlValidator/ValidatorError.cs diff --git a/src/YAMLValidator/ValidatorResults.cs b/src/YamlValidator/ValidatorResults.cs similarity index 100% rename from src/YAMLValidator/ValidatorResults.cs rename to src/YamlValidator/ValidatorResults.cs diff --git a/src/YAMLValidator/VerbosityData.cs b/src/YamlValidator/VerbosityData.cs similarity index 100% rename from src/YAMLValidator/VerbosityData.cs rename to src/YamlValidator/VerbosityData.cs diff --git a/src/YAMLValidator/YamlLoader.cs b/src/YamlValidator/YamlLoader.cs similarity index 100% rename from src/YAMLValidator/YamlLoader.cs rename to src/YamlValidator/YamlLoader.cs diff --git a/src/YAMLValidator/YAMLValidator.csproj b/src/YamlValidator/YamlValidator.csproj similarity index 100% rename from src/YAMLValidator/YAMLValidator.csproj rename to src/YamlValidator/YamlValidator.csproj From d9d4fb85ba64af2a43272ef4f1dfe5d1b4aac777 Mon Sep 17 00:00:00 2001 From: Amruth Baskar Date: Tue, 25 Jun 2024 10:11:31 -0700 Subject: [PATCH 10/11] explicit path type ternary --- src/YamlValidator/InputProcessor.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/YamlValidator/InputProcessor.cs b/src/YamlValidator/InputProcessor.cs index bd712d1a..c3e8337e 100644 --- a/src/YamlValidator/InputProcessor.cs +++ b/src/YamlValidator/InputProcessor.cs @@ -95,9 +95,8 @@ public static RootCommand GetRootCommand() validateCommand.SetHandler((pathOptionVal, schemaOptionVal) => { - // validation has completed, we either have a file or folder - var pathType = File.Exists(pathOptionVal) ? Constants.FileTypeName : - Constants.FolderTypeName; + var pathType = File.GetAttributes(pathOptionVal).HasFlag(FileAttributes.Directory) ? Constants.FolderTypeName : + Constants.FileTypeName; ProcessFiles(pathOptionVal, schemaOptionVal, pathType); }, pathOption, schemaOption); From afaf6d739d9152483f6040a1a9ee84d552ac0a9b Mon Sep 17 00:00:00 2001 From: Amruth Baskar Date: Tue, 25 Jun 2024 10:31:35 -0700 Subject: [PATCH 11/11] add comment for why unused value exists --- src/YamlValidator/Validator.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/YamlValidator/Validator.cs b/src/YamlValidator/Validator.cs index cb03262e..22e99756 100644 --- a/src/YamlValidator/Validator.cs +++ b/src/YamlValidator/Validator.cs @@ -32,6 +32,9 @@ public ValidatorResults Validate(JsonSchema schema, string yamlFileData) return new ValidatorResults(false, new List { new("Empty YAML file") }); } var results = schema.Evaluate(jsonData, _verbosityOptions); + + // not used but may help if we ever need to serialize the evaluation results into json format to feed into + // a vscode extension or other tool var output = JsonSerializer.Serialize(results, _serializerOptions); var schemaValidity = results.IsValid;