Skip to content

Commit

Permalink
Refactor option context (#1600)
Browse files Browse the repository at this point in the history
  • Loading branch information
BernieWhite authored Aug 27, 2023
1 parent 68563be commit 4c8f93f
Show file tree
Hide file tree
Showing 50 changed files with 907 additions and 748 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/analyze.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,19 @@ jobs:

- name: Upload results to security tab
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: reports/ps-rule-results.sarif

- name: Upload results
uses: actions/upload-artifact@v3
if: always()
with:
name: PSRule-Sarif
path: reports/ps-rule-results.sarif
retention-days: 1
if-no-files-found: error

devskim:
name: Analyze with DevSkim
runs-on: ubuntu-latest
Expand All @@ -63,9 +73,19 @@ jobs:

- name: Upload results to security tab
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: devskim-results.sarif

- name: Upload results
uses: actions/upload-artifact@v3
if: always()
with:
name: DevSkim-Sarif
path: devskim-results.sarif
retention-days: 1
if-no-files-found: error

codeql:
name: Analyze with CodeQL
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"APPSERVICEMININSTANCECOUNT",
"cmdlet",
"cmdlets",
"codeql",
"concat",
"datetime",
"deserialize",
Expand Down
24 changes: 23 additions & 1 deletion src/PSRule.Types/Converters/TypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ namespace PSRule.Converters
{
internal static class TypeConverter
{
private const string PROPERTY_BASEOBJECT = "BaseObject";

public static bool TryString(object o, out string? value)
{
value = null;
if (o == null) return false;
if (o is string s)
{
value = s;
Expand All @@ -20,7 +24,11 @@ public static bool TryString(object o, out string? value)
value = token.Value<string>();
return true;
}
value = null;
else if (TryGetValue(o, PROPERTY_BASEOBJECT, out var baseValue) && baseValue is string s_baseValue)
{
value = s_baseValue;
return true;
}
return false;
}

Expand Down Expand Up @@ -256,5 +264,19 @@ public static bool TryDouble(object o, bool convert, out double value)
value = default;
return false;
}

private static bool TryGetValue(object o, string propertyName, out object? value)
{
value = null;
if (o == null) return false;

var type = o.GetType();
if (type.TryGetPropertyInfo(propertyName, out var propertyInfo) && propertyInfo != null)
{
value = propertyInfo.GetValue(o);
return true;
}
return false;
}
}
}
20 changes: 19 additions & 1 deletion src/PSRule.Types/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,26 @@ public static bool TryGetStringArray(this IDictionary<string, object> dictionary
/// Duplicate keys are ignored.
/// </summary>
[DebuggerStepThrough]
public static void AddUnique(this IDictionary<string, object> dictionary, IEnumerable<KeyValuePair<string, object>> values)
public static void AddUnique<T>(this IDictionary<string, T> dictionary, IEnumerable<KeyValuePair<string, T>> values) where T : class
{
if (values == null) return;

foreach (var kv in values)
{
if (!dictionary.ContainsKey(kv.Key))
dictionary.Add(kv.Key, kv.Value);
}
}

/// <summary>
/// Add unique keys to the dictionary.
/// Duplicate keys are ignored.
/// </summary>
[DebuggerStepThrough]
public static void AddUnique(this IDictionary<string, string> dictionary, IEnumerable<KeyValuePair<string, string>> values)
{
if (values == null) return;

foreach (var kv in values)
{
if (!dictionary.ContainsKey(kv.Key))
Expand Down
2 changes: 1 addition & 1 deletion src/PSRule.Types/Options/BaselineOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public static BaselineOption Combine(BaselineOption o1, BaselineOption o2)
{
var result = new BaselineOption(o1)
{
Group = o1.Group ?? o2.Group,
Group = o1?.Group ?? o2?.Group,
};
return result;
}
Expand Down
26 changes: 13 additions & 13 deletions src/PSRule.Types/Options/ExecutionOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,32 +224,32 @@ public override int GetHashCode()
}

/// <summary>
/// Merge two option instances by repacing any unset properties from <paramref name="o1"/> with <paramref name="o2"/> values.
/// Merge two option instances by replacing any unset properties from <paramref name="o1"/> with <paramref name="o2"/> values.
/// Values from <paramref name="o1"/> that are set are not overridden.
/// </summary>
internal static ExecutionOption Combine(ExecutionOption o1, ExecutionOption o2)
{
var result = new ExecutionOption(o1)
{
DuplicateResourceId = o1.DuplicateResourceId ?? o2.DuplicateResourceId,
HashAlgorithm = o1.HashAlgorithm ?? o2.HashAlgorithm,
LanguageMode = o1.LanguageMode ?? o2.LanguageMode,
InitialSessionState = o1.InitialSessionState ?? o2.InitialSessionState,
SuppressionGroupExpired = o1.SuppressionGroupExpired ?? o2.SuppressionGroupExpired,
RuleExcluded = o1.RuleExcluded ?? o2.RuleExcluded,
RuleSuppressed = o1.RuleSuppressed ?? o2.RuleSuppressed,
AliasReference = o1.AliasReference ?? o2.AliasReference,
RuleInconclusive = o1.RuleInconclusive ?? o2.RuleInconclusive,
InvariantCulture = o1.InvariantCulture ?? o2.InvariantCulture,
UnprocessedObject = o1.UnprocessedObject ?? o2.UnprocessedObject,
DuplicateResourceId = o1?.DuplicateResourceId ?? o2?.DuplicateResourceId,
HashAlgorithm = o1?.HashAlgorithm ?? o2?.HashAlgorithm,
LanguageMode = o1?.LanguageMode ?? o2?.LanguageMode,
InitialSessionState = o1?.InitialSessionState ?? o2?.InitialSessionState,
SuppressionGroupExpired = o1?.SuppressionGroupExpired ?? o2?.SuppressionGroupExpired,
RuleExcluded = o1?.RuleExcluded ?? o2?.RuleExcluded,
RuleSuppressed = o1?.RuleSuppressed ?? o2?.RuleSuppressed,
AliasReference = o1?.AliasReference ?? o2?.AliasReference,
RuleInconclusive = o1?.RuleInconclusive ?? o2?.RuleInconclusive,
InvariantCulture = o1?.InvariantCulture ?? o2?.InvariantCulture,
UnprocessedObject = o1?.UnprocessedObject ?? o2?.UnprocessedObject,
};
return result;
}

/// <summary>
/// Determines how to handle duplicate resources identifiers during execution.
/// Regardless of the value, only the first resource will be used.
/// By defaut, an error is thrown.
/// By default, an error is thrown.
/// When set to Warn, a warning is generated.
/// When set to Debug, a message is written to the debug log.
/// When set to Ignore, no output will be displayed.
Expand Down
24 changes: 24 additions & 0 deletions src/PSRule.Types/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Reflection;

namespace PSRule
{
internal static class TypeExtensions
{
public static bool TryGetPropertyInfo(this Type type, string propertyName, out PropertyInfo? value)
{
value = null;
if (type == null || propertyName == null)
return false;

var propertyInfo = type.GetProperty(propertyName);
if (propertyInfo == null)
return false;

value = propertyInfo;
return true;
}
}
}
7 changes: 4 additions & 3 deletions src/PSRule/Commands/InvokeRuleBlockCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System.Management.Automation;
using PSRule.Configuration;
using PSRule.Definitions;
using PSRule.Pipeline;
using PSRule.Resources;
Expand All @@ -10,7 +11,7 @@
namespace PSRule.Commands
{
/// <summary>
/// An internal langauge command used to evaluate a rule script block.
/// An internal language command used to evaluate a rule script block.
/// </summary>
internal sealed class InvokeRuleBlockCommand : Cmdlet
{
Expand All @@ -37,14 +38,14 @@ protected override void ProcessRecord()
if (Body == null)
return;

// Evalute selector pre-condition
// Evaluate selector pre-condition
if (!AcceptsWith())
{
context.Writer.DebugMessage(PSRuleResources.DebugTargetTypeMismatch);
return;
}

// Evalute type pre-condition
// Evaluate type pre-condition
if (!AcceptsType())
{
context.Writer.DebugMessage(PSRuleResources.DebugTargetTypeMismatch);
Expand Down
13 changes: 6 additions & 7 deletions src/PSRule/Common/KeyMapDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,19 @@ protected internal KeyMapDictionary()
}

/// <summary>
/// Create a map intially populated with values copied from an existing instance.
/// Create a map initially populated with values copied from an existing instance.
/// </summary>
/// <param name="map">An existing instance to copy key/ values from.</param>
/// <exception cref="ArgumentNullException">Is raised if the map is null.</exception>
protected internal KeyMapDictionary(KeyMapDictionary<TValue> map)
{
if (map == null)
throw new ArgumentNullException(nameof(map));

_Map = new Dictionary<string, TValue>(map._Map, StringComparer.OrdinalIgnoreCase);
_Map = map == null ?
new Dictionary<string, TValue>(StringComparer.OrdinalIgnoreCase) :
new Dictionary<string, TValue>(map._Map, StringComparer.OrdinalIgnoreCase);
}

/// <summary>
/// Create a map intially populated with values copied from a dictionary.
/// Create a map initially populated with values copied from a dictionary.
/// </summary>
/// <param name="dictionary">An existing dictionary to copy key/ values from.</param>
protected internal KeyMapDictionary(IDictionary<string, TValue> dictionary)
Expand All @@ -47,7 +46,7 @@ protected internal KeyMapDictionary(IDictionary<string, TValue> dictionary)
}

/// <summary>
/// Create a map intially populated with values copied from a hashtable.
/// Create a map initially populated with values copied from a hashtable.
/// </summary>
/// <param name="hashtable">An existing hashtable to copy key/ values from.</param>
protected internal KeyMapDictionary(Hashtable hashtable)
Expand Down
26 changes: 18 additions & 8 deletions src/PSRule/Configuration/BindingOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@
// Licensed under the MIT License.

using System.ComponentModel;
using System.Diagnostics;

namespace PSRule.Configuration
{
internal static class BindingOptionExtensions
{
[DebuggerStepThrough]
public static StringComparer GetComparer(this BindingOption option)
{
return option.IgnoreCase.GetValueOrDefault(BindingOption.Default.IgnoreCase.Value) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
}
}

/// <summary>
/// Options that affect property binding of TargetName and TargetType.
/// </summary>
Expand Down Expand Up @@ -92,20 +102,20 @@ public override int GetHashCode()
}

/// <summary>
/// Merge two option instances by repacing any unset properties from <paramref name="o1"/> with <paramref name="o2"/> values.
/// Merge two option instances by replacing any unset properties from <paramref name="o1"/> with <paramref name="o2"/> values.
/// Values from <paramref name="o1"/> that are set are not overridden.
/// </summary>
internal static BindingOption Combine(BindingOption o1, BindingOption o2)
{
var result = new BindingOption(o1)
{
Field = o1.Field ?? o2.Field,
IgnoreCase = o1.IgnoreCase ?? o2.IgnoreCase,
NameSeparator = o1.NameSeparator ?? o2.NameSeparator,
PreferTargetInfo = o1.PreferTargetInfo ?? o2.PreferTargetInfo,
TargetName = o1.TargetName ?? o2.TargetName,
TargetType = o1.TargetType ?? o2.TargetType,
UseQualifiedName = o1.UseQualifiedName ?? o2.UseQualifiedName
Field = FieldMap.Combine(o1?.Field, o2?.Field),
IgnoreCase = o1?.IgnoreCase ?? o2?.IgnoreCase,
NameSeparator = o1?.NameSeparator ?? o2?.NameSeparator,
PreferTargetInfo = o1?.PreferTargetInfo ?? o2?.PreferTargetInfo,
TargetName = o1?.TargetName ?? o2?.TargetName,
TargetType = o1?.TargetType ?? o2?.TargetType,
UseQualifiedName = o1?.UseQualifiedName ?? o2?.UseQualifiedName
};
return result;
}
Expand Down
2 changes: 1 addition & 1 deletion src/PSRule/Configuration/ConventionOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ internal static ConventionOption Combine(ConventionOption o1, ConventionOption o
{
var result = new ConventionOption(o1)
{
Include = o1.Include ?? o2.Include
Include = o1?.Include ?? o2?.Include
};
return result;
}
Expand Down
10 changes: 10 additions & 0 deletions src/PSRule/Configuration/FieldMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,15 @@ internal IDictionary<string, string[]> GetFieldMap
{
get => _Map;
}

internal static FieldMap Combine(FieldMap m1, FieldMap m2)
{
if (m1 == null) return m2;
if (m2 == null) return m1;

var result = new FieldMap(m1);
result._Map.AddUnique(m2._Map);
return result;
}
}
}
4 changes: 2 additions & 2 deletions src/PSRule/Configuration/IncludeOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ internal static IncludeOption Combine(IncludeOption o1, IncludeOption o2)
{
var result = new IncludeOption(o1)
{
Path = o1.Path ?? o2.Path,
Module = o1.Module ?? o2.Module
Path = o1?.Path ?? o2?.Path,
Module = o1?.Module ?? o2?.Module
};
return result;
}
Expand Down
16 changes: 8 additions & 8 deletions src/PSRule/Configuration/InputOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,14 @@ internal static InputOption Combine(InputOption o1, InputOption o2)
{
var result = new InputOption(o1)
{
Format = o1.Format ?? o2.Format,
IgnoreGitPath = o1.IgnoreGitPath ?? o2.IgnoreGitPath,
IgnoreObjectSource = o1.IgnoreObjectSource ?? o2.IgnoreObjectSource,
IgnoreRepositoryCommon = o1.IgnoreRepositoryCommon ?? o2.IgnoreRepositoryCommon,
IgnoreUnchangedPath = o1.IgnoreUnchangedPath ?? o2.IgnoreUnchangedPath,
ObjectPath = o1.ObjectPath ?? o2.ObjectPath,
PathIgnore = o1.PathIgnore ?? o2.PathIgnore,
TargetType = o1.TargetType ?? o2.TargetType
Format = o1?.Format ?? o2?.Format,
IgnoreGitPath = o1?.IgnoreGitPath ?? o2?.IgnoreGitPath,
IgnoreObjectSource = o1?.IgnoreObjectSource ?? o2?.IgnoreObjectSource,
IgnoreRepositoryCommon = o1?.IgnoreRepositoryCommon ?? o2?.IgnoreRepositoryCommon,
IgnoreUnchangedPath = o1?.IgnoreUnchangedPath ?? o2?.IgnoreUnchangedPath,
ObjectPath = o1?.ObjectPath ?? o2?.ObjectPath,
PathIgnore = o1?.PathIgnore ?? o2?.PathIgnore,
TargetType = o1?.TargetType ?? o2?.TargetType
};
return result;
}
Expand Down
8 changes: 4 additions & 4 deletions src/PSRule/Configuration/LoggingOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ internal static LoggingOption Combine(LoggingOption o1, LoggingOption o2)
{
var result = new LoggingOption(o1)
{
LimitDebug = o1.LimitDebug ?? o2.LimitDebug,
LimitVerbose = o1.LimitVerbose ?? o2.LimitVerbose,
RuleFail = o1.RuleFail ?? o2.RuleFail,
RulePass = o1.RulePass ?? o2.RulePass
LimitDebug = o1?.LimitDebug ?? o2?.LimitDebug,
LimitVerbose = o1?.LimitVerbose ?? o2?.LimitVerbose,
RuleFail = o1?.RuleFail ?? o2?.RuleFail,
RulePass = o1?.RulePass ?? o2?.RulePass
};
return result;
}
Expand Down
Loading

0 comments on commit 4c8f93f

Please sign in to comment.