diff --git a/src/PAModel/packages.lock.json b/src/PAModel/packages.lock.json index a5711ce3..2a2f8c6d 100644 --- a/src/PAModel/packages.lock.json +++ b/src/PAModel/packages.lock.json @@ -46,46 +46,48 @@ }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "resolved": "8.0.0", + "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Logging": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "resolved": "8.0.0", + "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", "dependencies": { - "Microsoft.Extensions.DependencyInjection": "7.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", - "Microsoft.Extensions.Logging.Abstractions": "7.0.0", - "Microsoft.Extensions.Options": "7.0.0" + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" } }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==" + "resolved": "8.0.0", + "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "resolved": "8.0.0", + "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", - "Microsoft.Extensions.Primitives": "7.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==" + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, "Microsoft.PowerFx.Core": { "type": "Transitive", @@ -118,7 +120,7 @@ "microsoft.powerplatform.powerapps.persistence": { "type": "Project", "dependencies": { - "Microsoft.Extensions.Logging": "[7.0.0, )", + "Microsoft.Extensions.Logging": "[8.0.0, )", "Microsoft.PowerFx.Core": "[1.2.0, )", "YamlDotNet": "[15.1.6, )" } diff --git a/src/Persistence/packages.lock.json b/src/Persistence/packages.lock.json index 193c7068..80d0be12 100644 --- a/src/Persistence/packages.lock.json +++ b/src/Persistence/packages.lock.json @@ -4,14 +4,13 @@ "net8.0": { "Microsoft.Extensions.Logging": { "type": "Direct", - "requested": "[7.0.0, )", - "resolved": "7.0.0", - "contentHash": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", "dependencies": { - "Microsoft.Extensions.DependencyInjection": "7.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", - "Microsoft.Extensions.Logging.Abstractions": "7.0.0", - "Microsoft.Extensions.Options": "7.0.0" + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" } }, "Microsoft.Net.Compilers.Toolset.Framework": { @@ -44,35 +43,38 @@ }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "resolved": "8.0.0", + "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==" + "resolved": "8.0.0", + "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "resolved": "8.0.0", + "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", - "Microsoft.Extensions.Primitives": "7.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==" + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, "Microsoft.PowerFx.Transport.Attributes": { "type": "Transitive", diff --git a/src/Versions.props b/src/Versions.props index 58267d2c..1b4a289b 100644 --- a/src/Versions.props +++ b/src/Versions.props @@ -9,8 +9,7 @@ 6.0.0 6.12.0 4.3.0 - 7.0.0 - + 8.0.0 4.16.0 diff --git a/src/YamlValidator/Constants.cs b/src/YamlValidator/Constants.cs index e377efd7..c5c252a9 100644 --- a/src/YamlValidator/Constants.cs +++ b/src/YamlValidator/Constants.cs @@ -2,12 +2,12 @@ // Licensed under the MIT License. namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; -public class Constants + +public static class Constants { public const string FileTypeName = "file"; public const string FolderTypeName = "folder"; - public const string YamlFileExtension = ".yaml"; - public const string YmlFileExtension = ".yml"; + public const string YamlFileExtension = ".pa.yaml"; public const string JsonFileExtension = ".json"; public const string Verbose = "verbose"; diff --git a/src/YamlValidator/InputProcessor.cs b/src/YamlValidator/InputProcessor.cs index c3e8337e..b3d2e107 100644 --- a/src/YamlValidator/InputProcessor.cs +++ b/src/YamlValidator/InputProcessor.cs @@ -4,9 +4,9 @@ using System.CommandLine; namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; + public class InputProcessor { - private static void ProcessFiles(string path, string schema, string pathType) { // read only records @@ -19,6 +19,7 @@ private static void ProcessFiles(string path, string schema, string pathType) var orchestrator = new Orchestrator(fileLoader, schemaLoader, validator); orchestrator.RunValidation(filePathInfo); } + public static RootCommand GetRootCommand() { @@ -33,33 +34,32 @@ public static RootCommand GetRootCommand() var inputFilePath = result.GetValueForOption(pathOption); // either file or folder must be passed - var pathType = string.Empty; - if (string.IsNullOrEmpty(inputFilePath)) + if (string.IsNullOrWhiteSpace(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"; + result.ErrorMessage = $"The path '{inputFilePath}' does not exist"; } else if (Directory.Exists(inputFilePath)) { if (Directory.GetFiles(inputFilePath, $"*{Constants.YamlFileExtension}").Length == 0) { - result.ErrorMessage = "The input folder does not contain any yaml files"; + result.ErrorMessage = $"The folder '{inputFilePath}' does not contain any yaml files"; } } else if (File.Exists(inputFilePath)) { - if (Path.GetExtension(inputFilePath) != Constants.YamlFileExtension) + if (!inputFilePath.EndsWith(Constants.YamlFileExtension, StringComparison.OrdinalIgnoreCase)) { - result.ErrorMessage = "The input file must be a yaml file"; + result.ErrorMessage = $"The file '{inputFilePath}' must be a '{Constants.YamlFileExtension}' file"; } } }); - // assume local schema file exists in nuget package, use relative filepath for now + // 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", @@ -79,15 +79,15 @@ public static RootCommand GetRootCommand() } else if (!File.Exists(schemaPath)) { - result.ErrorMessage = "The schema file does not exist"; + result.ErrorMessage = $"The schema file '{schemaPath}' does not exist"; } }); // define root - var rootCommand = new RootCommand("YAML validator cli-tool"); + var rootCommand = new RootCommand("Power Apps YAML validator command line tool"); // validate command - var validateCommand = new Command("validate", "Validate the input yaml file") + var validateCommand = new Command("validate", "Validate the input Power Apps YAML file") { pathOption, schemaOption @@ -104,6 +104,5 @@ public static RootCommand GetRootCommand() rootCommand.AddCommand(validateCommand); return rootCommand; - } } diff --git a/src/YamlValidator/Orchestrator.cs b/src/YamlValidator/Orchestrator.cs index 71d04971..5c889020 100644 --- a/src/YamlValidator/Orchestrator.cs +++ b/src/YamlValidator/Orchestrator.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; + public class Orchestrator { private readonly YamlLoader _fileLoader; @@ -26,9 +27,10 @@ public void RunValidation(ValidationRequest inputData) foreach (var yamlFileData in yamlData) { - Console.WriteLine($"Validation for {yamlFileData.Key}"); + Console.WriteLine($"Validating '{yamlFileData.Key}'"); var result = _validator.Validate(serializedSchema, yamlFileData.Value); - Console.WriteLine($"Validation Result: {result.SchemaValid}"); + Console.WriteLine($"Validation {(result.SchemaValid ? "Passed" : "Failed")}"); + foreach (var error in result.TraversalResults) { Console.WriteLine($"{error}"); @@ -36,7 +38,4 @@ public void RunValidation(ValidationRequest inputData) Console.WriteLine(); } } - - - } diff --git a/src/YamlValidator/SchemaLoader.cs b/src/YamlValidator/SchemaLoader.cs index edce53c7..8130ecc8 100644 --- a/src/YamlValidator/SchemaLoader.cs +++ b/src/YamlValidator/SchemaLoader.cs @@ -4,6 +4,7 @@ using Json.Schema; namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; + public class SchemaLoader { private const string _schemaFolderPath = "subschemas"; @@ -23,6 +24,5 @@ public JsonSchema Load(string schemaPath) return node; } - } diff --git a/src/YamlValidator/Utility.cs b/src/YamlValidator/Utility.cs index c3ab709a..7ccc089b 100644 --- a/src/YamlValidator/Utility.cs +++ b/src/YamlValidator/Utility.cs @@ -4,6 +4,7 @@ using YamlDotNet.RepresentationModel; 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 46199731..55bb8b6a 100644 --- a/src/YamlValidator/ValidationRequest.cs +++ b/src/YamlValidator/ValidationRequest.cs @@ -2,4 +2,5 @@ // 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 22e99756..06d0c4c7 100644 --- a/src/YamlValidator/Validator.cs +++ b/src/YamlValidator/Validator.cs @@ -12,13 +12,11 @@ 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 ValidatorResults Validate(JsonSchema schema, string yamlFileData) @@ -34,7 +32,7 @@ public ValidatorResults Validate(JsonSchema schema, string yamlFileData) 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 + // a VSCode extension or other tool var output = JsonSerializer.Serialize(results, _serializerOptions); var schemaValidity = results.IsValid; @@ -51,9 +49,9 @@ public ValidatorResults Validate(JsonSchema schema, string yamlFileData) yamlValidatorErrors.Add(new ValidatorError(trace)); } } + IReadOnlyList fileErrors = yamlValidatorErrors; var finalResults = new ValidatorResults(results.IsValid, fileErrors); return finalResults; - } } diff --git a/src/YamlValidator/ValidatorError.cs b/src/YamlValidator/ValidatorError.cs index 3afec499..0ced0cfb 100644 --- a/src/YamlValidator/ValidatorError.cs +++ b/src/YamlValidator/ValidatorError.cs @@ -16,6 +16,7 @@ public ValidatorError(EvaluationResults results) SchemaPath = results.EvaluationPath.ToString(); Errors = results.Errors; } + public ValidatorError(string error) { InstanceLocation = ""; diff --git a/src/YamlValidator/ValidatorResults.cs b/src/YamlValidator/ValidatorResults.cs index 400e7a52..f396d34b 100644 --- a/src/YamlValidator/ValidatorResults.cs +++ b/src/YamlValidator/ValidatorResults.cs @@ -11,6 +11,5 @@ public ValidatorResults(bool schemaValid, IReadOnlyList traversa { SchemaValid = schemaValid; TraversalResults = traversalResults; - } } diff --git a/src/YamlValidator/YamlLoader.cs b/src/YamlValidator/YamlLoader.cs index 500da4d7..682e350c 100644 --- a/src/YamlValidator/YamlLoader.cs +++ b/src/YamlValidator/YamlLoader.cs @@ -6,7 +6,6 @@ namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class YamlLoader { - public IReadOnlyDictionary Load(string filePath, string pathType) { var deserializedYaml = new Dictionary(); @@ -29,5 +28,4 @@ public IReadOnlyDictionary Load(string filePath, string pathType return new ReadOnlyDictionary(deserializedYaml); } - } diff --git a/src/YamlValidator/YamlValidator.csproj b/src/YamlValidator/YamlValidator.csproj index e6653634..4a6b2b9f 100644 --- a/src/YamlValidator/YamlValidator.csproj +++ b/src/YamlValidator/YamlValidator.csproj @@ -18,7 +18,7 @@ - +