зеркало из https://github.com/microsoft/PSRule.git
Context refactoring (#2617)
* Context refactoring * Clean up * Fix linting
This commit is contained in:
Родитель
1b77ed73bf
Коммит
697c89fd6f
|
@ -614,49 +614,50 @@
|
|||
},
|
||||
"NuGet.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.11.1",
|
||||
"contentHash": "6ouw0UC3TGaFHNJyoEK2/Q5jSryRHzcbKGv9C0+t/TPnTP8PoLqnyFxO1dwmQUmJkWuKAUo6Vu0kIXHY/8LyKQ==",
|
||||
"resolved": "6.12.1",
|
||||
"contentHash": "nk8nTdhQl4x2VaAQUvefI7DDYAuBDlE+OZZRffm50Qx5dUAEq8wkc5JIqrN2lTEohObHPI/SXyG2UFdMQkrdyg==",
|
||||
"dependencies": {
|
||||
"NuGet.Frameworks": "6.11.1"
|
||||
"NuGet.Frameworks": "6.12.1"
|
||||
}
|
||||
},
|
||||
"NuGet.Configuration": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.11.1",
|
||||
"contentHash": "vbEe2acKrI2QmNx9U94ewhgUt6cLpwBeQfMtrie6NMz+GkJcX/4qIkKsX3SeBO4gFgCf8eeTyURl5hxPtiUctw==",
|
||||
"resolved": "6.12.1",
|
||||
"contentHash": "IRwlY1379ZgJ0oEJvjD+lDuOhJ5S1fsU5n/bEC5/i0+N9bo2WIMDAdaQ/qIdyK/gMJ/YWS+++GSX6rN7luqEvg==",
|
||||
"dependencies": {
|
||||
"NuGet.Common": "6.11.1",
|
||||
"NuGet.Common": "6.12.1",
|
||||
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||
}
|
||||
},
|
||||
"NuGet.Frameworks": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.11.1",
|
||||
"contentHash": "plTZ3ariSWQVsFn2mk83SsdmSg1VpgIMTSZpP/eSE/NNQF02p+M9ItxAYeUZBMX+cQ2nFkSwxQRJ0/fkaV9Hbg=="
|
||||
"resolved": "6.12.1",
|
||||
"contentHash": "kPaRD5RJC0ByUg+yGX6bDz5XHMI7OYmQwP8kbtef+vZ+csj/VDb5Bwas4ChxwhoAbI8lEvwP5/3aViQPpgNBow=="
|
||||
},
|
||||
"NuGet.Packaging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.11.1",
|
||||
"contentHash": "wiofIUUr7khwuaGXiOibMb7+dEkF97EVsAmzlaNc188HV9ujjqweQMuVCoAK2/MqXdhnrKjvicUfKo9CPsNnfg==",
|
||||
"resolved": "6.12.1",
|
||||
"contentHash": "6s5NO3VNX6fIx6GwuWZtIsal9W1xkelYd3Vg2KUAg1zGqnKC3wB5IZlombvVGVGcwyl/A+iDvpUwSvgeDoB3wA==",
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"NuGet.Configuration": "6.11.1",
|
||||
"NuGet.Versioning": "6.11.1",
|
||||
"NuGet.Configuration": "6.12.1",
|
||||
"NuGet.Versioning": "6.12.1",
|
||||
"System.Formats.Asn1": "8.0.1",
|
||||
"System.Security.Cryptography.Pkcs": "6.0.4"
|
||||
}
|
||||
},
|
||||
"NuGet.Protocol": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.11.1",
|
||||
"contentHash": "WkYlSuNHNt/j1tbHp/xjvwk2EsIdSM3raEjk3EfIFd62ER1+x4eC8/J1VKqnve6cTupF4LsuwD3Z4YCumnfCXw==",
|
||||
"resolved": "6.12.1",
|
||||
"contentHash": "VBN7OtG/Y9Rnj1WT3G8X88ZHu5Pq+yzca5Z6OI/FWXcENVAQkUl0ml6Cv8ghOqYyiuvnObGDV9oWLD/bIuVtDw==",
|
||||
"dependencies": {
|
||||
"NuGet.Packaging": "6.11.1"
|
||||
"NuGet.Packaging": "6.12.1"
|
||||
}
|
||||
},
|
||||
"NuGet.Versioning": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.11.1",
|
||||
"contentHash": "YNn3BB71F+guJW42TbAhGcMh3gpyqFMZcPVD9pm5vcvGivTALtRely/VCPWQQ6JQ5PfwIrjPaJMO7VnqyeK3rg=="
|
||||
"resolved": "6.12.1",
|
||||
"contentHash": "fJ6rFYANDnohFsdpaY79FvrJxI6murmoOxXz6nZlf819F48+IBKMnAIg3oIBRtZq5y498ObMtKnro5IitvizUg=="
|
||||
},
|
||||
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
||||
"type": "Transitive",
|
||||
|
@ -1646,7 +1647,7 @@
|
|||
"dependencies": {
|
||||
"Microsoft.PSRule.SDK": "[0.0.1, )",
|
||||
"Microsoft.PowerShell.SDK": "[7.4.6, )",
|
||||
"NuGet.Protocol": "[6.11.1, )",
|
||||
"NuGet.Protocol": "[6.12.1, )",
|
||||
"System.CommandLine": "[2.0.0-beta4.22272.1, )"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -70,7 +70,7 @@ internal sealed class ExportConventionCommand : LanguageBlock
|
|||
var context = RunspaceContext.CurrentThread;
|
||||
if (context == null) return;
|
||||
|
||||
var source = context!.Source!.File;
|
||||
var source = context.Source;
|
||||
var errorPreference = GetErrorActionPreference();
|
||||
var commentMetadata = GetCommentMetadata(source, MyInvocation.ScriptLineNumber, MyInvocation.OffsetInLine);
|
||||
var metadata = new ResourceMetadata
|
||||
|
|
|
@ -108,7 +108,7 @@ internal sealed class NewRuleDefinitionCommand : LanguageBlock
|
|||
throw new RuleException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.KeywordSourceScope, LanguageKeywords.Rule));
|
||||
|
||||
var context = RunspaceContext.CurrentThread;
|
||||
var source = context.Source.File;
|
||||
var source = context.Source;
|
||||
var errorPreference = GetErrorActionPreference();
|
||||
var metadata = GetCommentMetadata(source, MyInvocation.ScriptLineNumber, MyInvocation.OffsetInLine);
|
||||
var level = ResourceHelper.GetLevel(Level);
|
||||
|
|
|
@ -353,7 +353,7 @@ internal sealed class OrderedPropertiesContractResolver : DefaultContractResolve
|
|||
/// </summary>
|
||||
internal sealed class ResourceObjectJsonConverter : JsonConverter
|
||||
{
|
||||
private const string FIELD_APIVERSION = "apiVersion";
|
||||
private const string FIELD_API_VERSION = "apiVersion";
|
||||
private const string FIELD_KIND = "kind";
|
||||
private const string FIELD_METADATA = "metadata";
|
||||
private const string FIELD_SPEC = "spec";
|
||||
|
@ -363,10 +363,12 @@ internal sealed class ResourceObjectJsonConverter : JsonConverter
|
|||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
private readonly IResourceDiscoveryContext _Context;
|
||||
private readonly SpecFactory _Factory;
|
||||
|
||||
public ResourceObjectJsonConverter()
|
||||
public ResourceObjectJsonConverter(IResourceDiscoveryContext context)
|
||||
{
|
||||
_Context = context;
|
||||
_Factory = new SpecFactory();
|
||||
}
|
||||
|
||||
|
@ -388,7 +390,7 @@ internal sealed class ResourceObjectJsonConverter : JsonConverter
|
|||
|
||||
private IResource MapResource(JsonReader reader, JsonSerializer serializer)
|
||||
{
|
||||
reader.GetSourceExtent(RunspaceContext.CurrentThread.Source.File, out var extent);
|
||||
reader.GetSourceExtent(_Context.Source, out var extent);
|
||||
reader.SkipComments(out _);
|
||||
if (reader.TokenType != JsonToken.StartObject || !reader.Read())
|
||||
throw new PipelineSerializationException(PSRuleResources.ReadJsonFailed);
|
||||
|
@ -471,7 +473,7 @@ internal sealed class ResourceObjectJsonConverter : JsonConverter
|
|||
private static bool TryApiVersion(JsonReader reader, string propertyName, out string apiVersion)
|
||||
{
|
||||
apiVersion = null;
|
||||
if (propertyName == FIELD_APIVERSION)
|
||||
if (propertyName == FIELD_API_VERSION)
|
||||
{
|
||||
apiVersion = reader.ReadAsString();
|
||||
return true;
|
||||
|
@ -523,7 +525,7 @@ internal sealed class ResourceObjectJsonConverter : JsonConverter
|
|||
reader.SkipComments(out _);
|
||||
var deserializedSpec = serializer.Deserialize(reader, objectType: descriptor.SpecType);
|
||||
spec = descriptor.CreateInstance(
|
||||
source: RunspaceContext.CurrentThread.Source.File,
|
||||
source: _Context.Source,
|
||||
metadata: metadata,
|
||||
comment: comment,
|
||||
extent: extent,
|
||||
|
@ -665,11 +667,13 @@ internal sealed class LanguageExpressionJsonConverter : JsonConverter
|
|||
{
|
||||
private const string OPERATOR_IF = "if";
|
||||
|
||||
private readonly IResourceDiscoveryContext _Context;
|
||||
private readonly LanguageExpressionFactory _Factory;
|
||||
private readonly FunctionBuilder _FunctionBuilder;
|
||||
|
||||
public LanguageExpressionJsonConverter()
|
||||
public LanguageExpressionJsonConverter(IResourceDiscoveryContext context)
|
||||
{
|
||||
_Context = context;
|
||||
_Factory = new LanguageExpressionFactory();
|
||||
_FunctionBuilder = new FunctionBuilder();
|
||||
}
|
||||
|
@ -946,7 +950,7 @@ internal sealed class LanguageExpressionJsonConverter : JsonConverter
|
|||
if (_Factory.TryDescriptor(type, out var descriptor))
|
||||
{
|
||||
expression = (T)descriptor.CreateInstance(
|
||||
source: RunspaceContext.CurrentThread.Source.File,
|
||||
source: _Context.Source,
|
||||
properties: properties
|
||||
);
|
||||
return expression != null;
|
||||
|
|
|
@ -12,7 +12,6 @@ using PSRule.Definitions.Expressions;
|
|||
using PSRule.Host;
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Pipeline.Emitters;
|
||||
using PSRule.Runtime;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
@ -479,16 +478,18 @@ internal sealed class FieldYamlTypeInspector : ReflectionTypeInspector
|
|||
/// </summary>
|
||||
internal sealed class ResourceNodeDeserializer : INodeDeserializer
|
||||
{
|
||||
private const string FIELD_APIVERSION = "apiVersion";
|
||||
private const string FIELD_API_VERSION = "apiVersion";
|
||||
private const string FIELD_KIND = "kind";
|
||||
private const string FIELD_METADATA = "metadata";
|
||||
private const string FIELD_SPEC = "spec";
|
||||
|
||||
private readonly IResourceDiscoveryContext _Context;
|
||||
private readonly INodeDeserializer _Next;
|
||||
private readonly SpecFactory _Factory;
|
||||
|
||||
public ResourceNodeDeserializer(INodeDeserializer next)
|
||||
public ResourceNodeDeserializer(IResourceDiscoveryContext context, INodeDeserializer next)
|
||||
{
|
||||
_Context = context;
|
||||
_Next = next;
|
||||
_Factory = new SpecFactory();
|
||||
}
|
||||
|
@ -497,7 +498,7 @@ internal sealed class ResourceNodeDeserializer : INodeDeserializer
|
|||
{
|
||||
if (typeof(ResourceObject).IsAssignableFrom(expectedType))
|
||||
{
|
||||
var comment = reader.Current == null || RunspaceContext.CurrentThread == null ? null : HostHelper.GetCommentMeta(RunspaceContext.CurrentThread.Source?.File, (int)reader.Current.Start.Line - 2, (int)reader.Current.Start.Column);
|
||||
var comment = reader.Current == null ? null : GetCommentMetadata(reader.Current.Start.Line - 2, reader.Current.Start.Column);
|
||||
var resource = MapResource(reader, nestedObjectDeserializer, comment, rootDeserializer);
|
||||
value = new ResourceObject(resource);
|
||||
return true;
|
||||
|
@ -516,7 +517,7 @@ internal sealed class ResourceNodeDeserializer : INodeDeserializer
|
|||
ResourceMetadata? metadata = null;
|
||||
if (reader.TryConsume<MappingStart>(out var mappingStart) && mappingStart != null)
|
||||
{
|
||||
var extent = new SourceExtent(RunspaceContext.CurrentThread!.Source!.File, (int?)mappingStart.Start.Line, (int?)mappingStart.Start.Column);
|
||||
var extent = GetSourceExtent(mappingStart.Start.Line, mappingStart.Start.Column);
|
||||
while (reader.TryConsume<Scalar>(out var scalar) && scalar != null)
|
||||
{
|
||||
// Read apiVersion
|
||||
|
@ -553,7 +554,7 @@ internal sealed class ResourceNodeDeserializer : INodeDeserializer
|
|||
private static bool TryApiVersion(IParser reader, Scalar scalar, out string? apiVersion)
|
||||
{
|
||||
apiVersion = null;
|
||||
if (scalar.Value == FIELD_APIVERSION)
|
||||
if (scalar.Value == FIELD_API_VERSION)
|
||||
{
|
||||
apiVersion = reader.Consume<Scalar>().Value;
|
||||
return true;
|
||||
|
@ -572,6 +573,16 @@ internal sealed class ResourceNodeDeserializer : INodeDeserializer
|
|||
return false;
|
||||
}
|
||||
|
||||
private CommentMetadata? GetCommentMetadata(long line, long column)
|
||||
{
|
||||
return _Context == null || _Context.Source == null ? null : HostHelper.GetCommentMeta(_Context.Source, (int)line, (int)column);
|
||||
}
|
||||
|
||||
private SourceExtent GetSourceExtent(long? line, long? column)
|
||||
{
|
||||
return new SourceExtent(_Context.Source, (int?)line, (int?)column);
|
||||
}
|
||||
|
||||
private bool TryMetadata(IParser reader, Scalar scalar, Func<IParser, Type, object?> nestedObjectDeserializer, out ResourceMetadata? metadata, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
metadata = null;
|
||||
|
@ -617,12 +628,14 @@ internal sealed class LanguageExpressionDeserializer : INodeDeserializer
|
|||
{
|
||||
private const string OPERATOR_IF = "if";
|
||||
|
||||
private readonly IResourceDiscoveryContext _Context;
|
||||
private readonly INodeDeserializer _Next;
|
||||
private readonly LanguageExpressionFactory _Factory;
|
||||
private readonly FunctionBuilder _FunctionBuilder;
|
||||
|
||||
public LanguageExpressionDeserializer(INodeDeserializer next)
|
||||
public LanguageExpressionDeserializer(IResourceDiscoveryContext context, INodeDeserializer next)
|
||||
{
|
||||
_Context = context;
|
||||
_Next = next;
|
||||
_Factory = new LanguageExpressionFactory();
|
||||
_FunctionBuilder = new FunctionBuilder();
|
||||
|
@ -874,7 +887,7 @@ internal sealed class LanguageExpressionDeserializer : INodeDeserializer
|
|||
expression = null;
|
||||
if (_Factory.TryDescriptor(type, out var descriptor))
|
||||
{
|
||||
expression = (T)descriptor.CreateInstance(RunspaceContext.CurrentThread!.Source!.File, properties);
|
||||
expression = (T)descriptor.CreateInstance(_Context.Source, properties);
|
||||
return expression != null;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -18,6 +18,11 @@ internal interface IResourceDiscoveryContext
|
|||
/// </summary>
|
||||
IPipelineWriter Writer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current source file.
|
||||
/// </summary>
|
||||
ISourceFile? Source { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Enter a language scope.
|
||||
/// </summary>
|
||||
|
|
|
@ -16,7 +16,7 @@ internal sealed class ResourceBuilder
|
|||
private readonly List<ILanguageBlock> _Output;
|
||||
private readonly IDeserializer _Deserializer;
|
||||
|
||||
internal ResourceBuilder()
|
||||
internal ResourceBuilder(IResourceDiscoveryContext context)
|
||||
{
|
||||
_Output = new List<ILanguageBlock>();
|
||||
_Deserializer = new DeserializerBuilder()
|
||||
|
@ -29,7 +29,7 @@ internal sealed class ResourceBuilder
|
|||
.WithTypeConverter(new StringArrayMapConverter())
|
||||
.WithTypeConverter(new StringArrayConverter())
|
||||
.WithNodeDeserializer(
|
||||
inner => new ResourceNodeDeserializer(new LanguageExpressionDeserializer(inner)),
|
||||
inner => new ResourceNodeDeserializer(context, new LanguageExpressionDeserializer(context, inner)),
|
||||
s => s.InsteadOf<ObjectNodeDeserializer>())
|
||||
.Build();
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PSRule.Definitions;
|
||||
|
||||
/// <summary>
|
||||
/// A resource object.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{Block.Kind} - {Block.Id.Value}")]
|
||||
public sealed class ResourceObject
|
||||
{
|
||||
internal ResourceObject(IResource block)
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Diagnostics;
|
||||
using PSRule.Definitions.Expressions;
|
||||
using PSRule.Resources;
|
||||
using PSRule.Runtime;
|
||||
|
||||
namespace PSRule.Definitions.SuppressionGroups;
|
||||
|
||||
[DebuggerDisplay("{Id.Value}")]
|
||||
internal sealed class SuppressionGroupVisitor
|
||||
{
|
||||
private readonly LanguageExpressionOuterFn _Fn;
|
||||
|
@ -20,6 +22,7 @@ internal sealed class SuppressionGroupVisitor
|
|||
Source = source;
|
||||
InstanceId = Guid.NewGuid();
|
||||
Rule = spec.Rule;
|
||||
Info = info;
|
||||
_Info = new SuppressionInfo(id, info);
|
||||
_Fn = new LanguageExpressionBuilder()
|
||||
.WithRule(Rule)
|
||||
|
@ -69,6 +72,8 @@ internal sealed class SuppressionGroupVisitor
|
|||
|
||||
public ResourceId Id { get; }
|
||||
|
||||
public IResourceHelpInfo Info { get; }
|
||||
|
||||
public ISourceFile Source { get; }
|
||||
|
||||
public Guid InstanceId { get; }
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using PSRule.Annotations;
|
||||
using PSRule.Converters.Yaml;
|
||||
|
@ -104,11 +105,10 @@ internal static class HostHelper
|
|||
/// </summary>
|
||||
internal static CommentMetadata GetCommentMeta(ISourceFile file, int lineNumber, int offset)
|
||||
{
|
||||
var context = RunspaceContext.CurrentThread;
|
||||
if (lineNumber < 0 || RunspaceContext.CurrentThread.IsScope(RunspaceScope.None) || context.Source.SourceContentCache == null)
|
||||
if (lineNumber < 0 || !file.Exists())
|
||||
return new CommentMetadata();
|
||||
|
||||
var lines = context.Source.SourceContentCache;
|
||||
var lines = File.ReadAllLines(file.Path, Encoding.UTF8); ;
|
||||
var i = lineNumber;
|
||||
var comments = new List<string>();
|
||||
|
||||
|
@ -263,7 +263,7 @@ internal static class HostHelper
|
|||
.WithTypeConverter(new PSObjectYamlTypeConverter())
|
||||
.WithNodeTypeResolver(new PSOptionYamlTypeResolver())
|
||||
.WithNodeDeserializer(
|
||||
inner => new ResourceNodeDeserializer(new LanguageExpressionDeserializer(inner)),
|
||||
inner => new ResourceNodeDeserializer(context, new LanguageExpressionDeserializer(context, inner)),
|
||||
s => s.InsteadOf<ObjectNodeDeserializer>())
|
||||
.Build();
|
||||
|
||||
|
@ -292,7 +292,9 @@ internal static class HostHelper
|
|||
continue;
|
||||
|
||||
if (item.Visit(visitor))
|
||||
{
|
||||
result.Add(item.Block);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
@ -321,10 +323,10 @@ internal static class HostHelper
|
|||
{
|
||||
DateTimeZoneHandling = DateTimeZoneHandling.Utc
|
||||
};
|
||||
deserializer.Converters.Add(new ResourceObjectJsonConverter());
|
||||
deserializer.Converters.Add(new ResourceObjectJsonConverter(context));
|
||||
deserializer.Converters.Add(new FieldMapJsonConverter());
|
||||
deserializer.Converters.Add(new StringArrayJsonConverter());
|
||||
deserializer.Converters.Add(new LanguageExpressionJsonConverter());
|
||||
deserializer.Converters.Add(new LanguageExpressionJsonConverter(context));
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -351,9 +353,11 @@ internal static class HostHelper
|
|||
reader.SkipComments(out _);
|
||||
while (reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
var value = deserializer.Deserialize<ResourceObject>(reader);
|
||||
if (value?.Block != null && value.Visit(visitor))
|
||||
result.Add(value.Block);
|
||||
var item = deserializer.Deserialize<ResourceObject>(reader);
|
||||
if (item?.Block != null && item.Visit(visitor))
|
||||
{
|
||||
result.Add(item.Block);
|
||||
}
|
||||
|
||||
// Consume all end objects at the end of each resource
|
||||
while (reader.TryConsume(JsonToken.EndObject)) { }
|
||||
|
@ -624,7 +628,7 @@ internal static class HostHelper
|
|||
}
|
||||
|
||||
}
|
||||
return results.Values.ToArray();
|
||||
return [.. results.Values];
|
||||
}
|
||||
|
||||
private static Baseline[] ToBaselineV1(IEnumerable<ILanguageBlock> blocks, RunspaceContext context)
|
||||
|
@ -695,7 +699,7 @@ internal static class HostHelper
|
|||
if (!results.ContainsKey(block.Name))
|
||||
results[block.Name] = block;
|
||||
}
|
||||
return results.Values.ToArray();
|
||||
return [.. results.Values];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -858,7 +862,7 @@ internal static class HostHelper
|
|||
? new RuleHelpInfo(
|
||||
name: name,
|
||||
displayName: defaultDisplayName ?? name,
|
||||
moduleName: context.Source.File.Module,
|
||||
moduleName: context.Source.Module,
|
||||
synopsis: InfoString.Create(defaultSynopsis),
|
||||
description: defaultDescription,
|
||||
recommendation: defaultRecommendation
|
||||
|
@ -866,7 +870,7 @@ internal static class HostHelper
|
|||
: new RuleHelpInfo(
|
||||
name: name,
|
||||
displayName: document.Name ?? defaultDisplayName ?? name,
|
||||
moduleName: context.Source.File.Module,
|
||||
moduleName: context.Source.Module,
|
||||
synopsis: document.Synopsis ?? new InfoString(defaultSynopsis),
|
||||
description: document.Description ?? defaultDescription,
|
||||
recommendation: document.Recommendation ?? defaultRecommendation ?? document.Synopsis ?? InfoString.Create(defaultSynopsis)
|
||||
|
@ -895,7 +899,7 @@ internal static class HostHelper
|
|||
{
|
||||
path = null;
|
||||
culture = null;
|
||||
if (string.IsNullOrEmpty(context.Source.File.HelpPath))
|
||||
if (string.IsNullOrEmpty(context.Source.HelpPath))
|
||||
return false;
|
||||
|
||||
var helpFileName = string.Concat(name, Markdown_Extension);
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Definitions;
|
||||
using PSRule.Resources;
|
||||
using PSRule.Runtime;
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
#nullable enable
|
||||
|
||||
/// <summary>
|
||||
/// Define a context used for early stage resource discovery.
|
||||
/// </summary>
|
||||
|
@ -13,14 +16,19 @@ internal sealed class ResourceCacheDiscoveryContext(IPipelineWriter writer) : IR
|
|||
{
|
||||
public IPipelineWriter Writer { get; } = writer;
|
||||
|
||||
public ISourceFile? Source { get; private set; }
|
||||
|
||||
public void EnterLanguageScope(ISourceFile file)
|
||||
{
|
||||
if (!file.Exists())
|
||||
throw new FileNotFoundException(PSRuleResources.ScriptNotFound, file.Path);
|
||||
|
||||
Source = file;
|
||||
}
|
||||
|
||||
public void ExitLanguageScope(ISourceFile file)
|
||||
{
|
||||
|
||||
Source = null;
|
||||
}
|
||||
|
||||
public void PopScope(RunspaceScope scope)
|
||||
|
@ -33,3 +41,5 @@ internal sealed class ResourceCacheDiscoveryContext(IPipelineWriter writer) : IR
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
#nullable restore
|
||||
|
|
|
@ -11,7 +11,6 @@ using PSRule.Pipeline;
|
|||
using PSRule.Resources;
|
||||
using PSRule.Rules;
|
||||
using PSRule.Runtime.Binding;
|
||||
using static PSRule.Pipeline.PipelineContext;
|
||||
|
||||
namespace PSRule.Runtime;
|
||||
|
||||
|
@ -24,7 +23,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
{
|
||||
private const string SOURCE_OUTCOME_FAIL = "Rule.Outcome.Fail";
|
||||
private const string SOURCE_OUTCOME_PASS = "Rule.Outcome.Pass";
|
||||
private const string ERRORID_INVALIDRULERESULT = "PSRule.Runtime.InvalidRuleResult";
|
||||
private const string ERROR_ID_INVALID_RULE_RESULT = "PSRule.Runtime.InvalidRuleResult";
|
||||
private const string WARN_KEY_SEPARATOR = "_";
|
||||
|
||||
[ThreadStatic]
|
||||
|
@ -99,7 +98,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
|
||||
internal TargetObject? TargetObject { get; private set; }
|
||||
|
||||
internal SourceScope? Source { get; private set; }
|
||||
public ISourceFile? Source { get; private set; }
|
||||
|
||||
internal ILanguageScope? LanguageScope
|
||||
{
|
||||
|
@ -247,7 +246,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
PSRuleResources.InvalidRuleResult,
|
||||
RuleBlock?.Id
|
||||
)),
|
||||
errorId: ERRORID_INVALIDRULERESULT,
|
||||
errorId: ERROR_ID_INVALID_RULE_RESULT,
|
||||
errorCategory: ErrorCategory.InvalidResult,
|
||||
targetObject: null
|
||||
));
|
||||
|
@ -528,7 +527,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
if (TargetObject != null && LanguageScope != null)
|
||||
Binding = LanguageScope.Bind(TargetObject);
|
||||
|
||||
Source = new SourceScope(file);
|
||||
Source = file;
|
||||
}
|
||||
|
||||
public void ExitLanguageScope(ISourceFile file)
|
||||
|
@ -562,7 +561,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
|
||||
public bool TrySelector(string name)
|
||||
{
|
||||
return TrySelector(ResourceHelper.GetRuleId(Source?.File?.Module, name, ResourceIdKind.Unknown));
|
||||
return TrySelector(ResourceHelper.GetRuleId(Source?.Module, name, ResourceIdKind.Unknown));
|
||||
}
|
||||
|
||||
public bool TrySelector(ResourceId id)
|
||||
|
@ -659,7 +658,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
if (LanguageScope == null) throw new Exception("Can not call out of scope.");
|
||||
|
||||
ResourceHelper.ParseIdString(LanguageScope.Name, id, out var scopeName, out var name);
|
||||
return !Pipeline.LanguageScope.TryScope(scopeName, out var scope) || string.IsNullOrEmpty(name) ? null : scope.GetService(name!);
|
||||
return !Pipeline.LanguageScope.TryScope(scopeName, out var scope) || string.IsNullOrEmpty(name) ? null : scope.GetService(name);
|
||||
}
|
||||
|
||||
private void RunConventionInitialize()
|
||||
|
@ -782,7 +781,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
public string? GetLocalizedPath(string file, out string? culture)
|
||||
{
|
||||
culture = null;
|
||||
if (string.IsNullOrEmpty(Source?.File.HelpPath))
|
||||
if (string.IsNullOrEmpty(Source?.HelpPath))
|
||||
return null;
|
||||
|
||||
var cultures = LanguageScope?.Culture;
|
||||
|
@ -795,7 +794,7 @@ internal sealed class RunspaceContext : IDisposable, ILogger, IScriptResourceDis
|
|||
|
||||
for (var i = 0; cultures != null && i < cultures.Length; i++)
|
||||
{
|
||||
var path = Path.Combine(Source?.File.HelpPath, cultures[i], file);
|
||||
var path = Path.Combine(Source?.HelpPath, cultures[i], file);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
culture = cultures[i];
|
||||
|
|
|
@ -16,6 +16,8 @@ using YamlDotNet.Serialization;
|
|||
|
||||
namespace PSRule;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public sealed class BaselineTests : ContextBaseTests
|
||||
{
|
||||
private const string BaselineYamlFileName = "Baseline.Rule.yaml";
|
||||
|
@ -161,14 +163,14 @@ public sealed class BaselineTests : ContextBaseTests
|
|||
var actual = (JArray)JsonConvert.DeserializeObject<dynamic>(json);
|
||||
|
||||
// TestBaseline1
|
||||
Assert.Equal("github.com/microsoft/PSRule/v1", actual[0]["apiVersion"]);
|
||||
Assert.Equal("Baseline", actual[0]["kind"]);
|
||||
Assert.Equal("TestBaseline1", actual[0]["metadata"]["name"]);
|
||||
Assert.NotNull(actual[0]["spec"]);
|
||||
Assert.Equal("WithBaseline", actual[0]["spec"]["rule"]["include"][0]);
|
||||
Assert.Equal("value1", actual[0]["spec"]["configuration"]["key1"]);
|
||||
Assert.Equal("abc", actual[0]["spec"]["configuration"]["key2"][0]["value1"]);
|
||||
Assert.Equal("def", actual[0]["spec"]["configuration"]["key2"][1]["value2"]);
|
||||
Assert.Equal("github.com/microsoft/PSRule/v1", actual?[0]["apiVersion"]);
|
||||
Assert.Equal("Baseline", actual?[0]["kind"]);
|
||||
Assert.Equal("TestBaseline1", actual?[0]["metadata"]?["name"]);
|
||||
Assert.NotNull(actual?[0]["spec"]);
|
||||
Assert.Equal("WithBaseline", actual?[0]["spec"]?["rule"]?["include"]?[0]);
|
||||
Assert.Equal("value1", actual?[0]["spec"]?["configuration"]?["key1"]);
|
||||
Assert.Equal("abc", actual?[0]["spec"]?["configuration"]?["key2"]?[0]?["value1"]);
|
||||
Assert.Equal("def", actual?[0]["spec"]?["configuration"]?["key2"]?[1]?["value2"]);
|
||||
}
|
||||
|
||||
#region Helper methods
|
||||
|
@ -195,3 +197,5 @@ public sealed class BaselineTests : ContextBaseTests
|
|||
|
||||
#endregion Helper methods
|
||||
}
|
||||
|
||||
#nullable restore
|
||||
|
|
|
@ -11,13 +11,13 @@ metadata:
|
|||
name: SuppressWithTargetName
|
||||
spec:
|
||||
rule:
|
||||
- 'FromFile1'
|
||||
- 'FromFile2'
|
||||
- 'FromFile1'
|
||||
- 'FromFile2'
|
||||
if:
|
||||
name: '.'
|
||||
in:
|
||||
- 'TestObject1'
|
||||
- 'TestObject2'
|
||||
- 'TestObject1'
|
||||
- 'TestObject2'
|
||||
|
||||
---
|
||||
# Synopsis: Ignore test objects by type.
|
||||
|
@ -27,27 +27,27 @@ metadata:
|
|||
name: SuppressWithTestType
|
||||
spec:
|
||||
rule:
|
||||
- 'FromFile3'
|
||||
- 'FromFile5'
|
||||
- 'FromFile3'
|
||||
- 'FromFile5'
|
||||
if:
|
||||
type: '.'
|
||||
equals: 'TestType'
|
||||
|
||||
---
|
||||
# Synopsis: Suppress with non-production tag
|
||||
# Synopsis: Suppress with non-production tag.
|
||||
apiVersion: github.com/microsoft/PSRule/v1
|
||||
kind: SuppressionGroup
|
||||
metadata:
|
||||
name: SuppressWithNonProdTag
|
||||
spec:
|
||||
rule:
|
||||
- '.\WithTag2'
|
||||
- '.\WithTag3'
|
||||
- '.\WithTag2'
|
||||
- '.\WithTag3'
|
||||
if:
|
||||
field: 'tags.env'
|
||||
in:
|
||||
- 'dev'
|
||||
- 'test'
|
||||
- 'dev'
|
||||
- 'test'
|
||||
|
||||
---
|
||||
# Synopsis: Suppress with expiry.
|
||||
|
@ -58,13 +58,13 @@ metadata:
|
|||
spec:
|
||||
expiresOn: '2022-01-01T00:00:00Z'
|
||||
rule:
|
||||
- '.\WithTag2'
|
||||
- '.\WithTag3'
|
||||
- '.\WithTag2'
|
||||
- '.\WithTag3'
|
||||
if:
|
||||
field: 'tags.env'
|
||||
in:
|
||||
- 'dev'
|
||||
- 'test'
|
||||
- 'dev'
|
||||
- 'test'
|
||||
|
||||
---
|
||||
# Synopsis: Suppress by scope.
|
||||
|
@ -74,8 +74,8 @@ metadata:
|
|||
name: SuppressByScope
|
||||
spec:
|
||||
rule:
|
||||
- 'FromFile1'
|
||||
- 'FromFile2'
|
||||
- 'FromFile1'
|
||||
- 'FromFile2'
|
||||
if:
|
||||
scope: .
|
||||
startsWith: '/'
|
||||
|
|
Загрузка…
Ссылка в новой задаче