зеркало из https://github.com/microsoft/PSRule.git
Родитель
f290f051cc
Коммит
0d57f6da36
|
@ -1,6 +1,9 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
- Fix YAML options file discovery issue in dotted directory. [#232](https://github.com/BernieWhite/PSRule/issues/232)
|
||||
- PSRule options are now displayed as YAML instead of complex object. [#233](https://github.com/BernieWhite/PSRule/issues/233)
|
||||
|
||||
## v0.7.0
|
||||
|
||||
What's changed since v0.6.0:
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using PSRule.Resources;
|
||||
using Newtonsoft.Json;
|
||||
using PSRule.Resources;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Text.RegularExpressions;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
|
@ -23,6 +23,8 @@ namespace PSRule.Configuration
|
|||
{
|
||||
private const string DEFAULT_FILENAME = "ps-rule.yaml";
|
||||
|
||||
private string SourcePath;
|
||||
|
||||
private static readonly PSRuleOption Default = new PSRuleOption
|
||||
{
|
||||
Binding = BindingOption.Default,
|
||||
|
@ -50,8 +52,10 @@ namespace PSRule.Configuration
|
|||
Pipeline = new PipelineHook();
|
||||
}
|
||||
|
||||
public PSRuleOption(PSRuleOption option)
|
||||
private PSRuleOption(string sourcePath, PSRuleOption option)
|
||||
{
|
||||
SourcePath = sourcePath;
|
||||
|
||||
// Set from existing option instance
|
||||
Baseline = new BaselineOption(option.Baseline);
|
||||
Binding = new BindingOption(option.Binding);
|
||||
|
@ -98,21 +102,34 @@ namespace PSRule.Configuration
|
|||
/// </summary>
|
||||
public SuppressionOption Suppression { get; set; }
|
||||
|
||||
[YamlIgnore()]
|
||||
[YamlIgnore]
|
||||
[JsonIgnore]
|
||||
public PipelineHook Pipeline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return options as YAML.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Called from PowerShell.
|
||||
/// </remarks>
|
||||
public string ToYaml()
|
||||
{
|
||||
var s = new SerializerBuilder()
|
||||
.WithNamingConvention(new CamelCaseNamingConvention())
|
||||
.Build();
|
||||
var yaml = GetYaml();
|
||||
if (string.IsNullOrEmpty(SourcePath))
|
||||
{
|
||||
return yaml;
|
||||
}
|
||||
|
||||
return s.Serialize(this);
|
||||
return string.Concat(
|
||||
string.Format(PSRuleResources.OptionsSourceComment, SourcePath),
|
||||
Environment.NewLine,
|
||||
yaml
|
||||
);
|
||||
}
|
||||
|
||||
public PSRuleOption Clone()
|
||||
{
|
||||
return new PSRuleOption(this);
|
||||
return new PSRuleOption(sourcePath: SourcePath, option: this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -123,7 +140,7 @@ namespace PSRule.Configuration
|
|||
{
|
||||
// Get a rooted file path instead of directory or relative path
|
||||
var filePath = GetFilePath(path: path);
|
||||
File.WriteAllText(path: filePath, contents: ToYaml());
|
||||
File.WriteAllText(path: filePath, contents: GetYaml());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -150,8 +167,7 @@ namespace PSRule.Configuration
|
|||
return Default.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
return FromYaml(yaml: File.ReadAllText(filePath));
|
||||
return FromYaml(path: filePath, yaml: File.ReadAllText(filePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -169,21 +185,28 @@ namespace PSRule.Configuration
|
|||
{
|
||||
return new PSRuleOption();
|
||||
}
|
||||
|
||||
return FromYaml(yaml: File.ReadAllText(filePath));
|
||||
return FromYaml(path: filePath, yaml: File.ReadAllText(filePath));
|
||||
}
|
||||
|
||||
public static PSRuleOption FromYaml(string yaml)
|
||||
public static PSRuleOption FromYaml(string path, string yaml)
|
||||
{
|
||||
var d = new DeserializerBuilder()
|
||||
.IgnoreUnmatchedProperties()
|
||||
.WithNamingConvention(new CamelCaseNamingConvention())
|
||||
.WithTypeConverter(new SuppressionRuleYamlTypeConverter())
|
||||
.Build();
|
||||
|
||||
return d.Deserialize<PSRuleOption>(yaml) ?? new PSRuleOption();
|
||||
var option = d.Deserialize<PSRuleOption>(yaml) ?? new PSRuleOption();
|
||||
option.SourcePath = path;
|
||||
return option;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set working path from PowerShell host environment.
|
||||
/// </summary>
|
||||
/// <param name="executionContext">An $ExecutionContext object.</param>
|
||||
/// <remarks>
|
||||
/// Called from PowerShell.
|
||||
/// </remarks>
|
||||
public static void UseExecutionContext(EngineIntrinsics executionContext)
|
||||
{
|
||||
if (executionContext == null)
|
||||
|
@ -389,15 +412,19 @@ namespace PSRule.Configuration
|
|||
var rootedPath = GetRootedPath(path);
|
||||
if (Path.HasExtension(rootedPath))
|
||||
{
|
||||
return rootedPath;
|
||||
var ext = Path.GetExtension(rootedPath);
|
||||
if (string.Equals(ext, ".yaml", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".yml", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return rootedPath;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if default files exist and
|
||||
return UseFilePath(path: path, name: "ps-rule.yaml") ??
|
||||
UseFilePath(path: path, name: "ps-rule.yml") ??
|
||||
UseFilePath(path: path, name: "psrule.yaml") ??
|
||||
UseFilePath(path: path, name: "psrule.yml") ??
|
||||
Path.Combine(path, DEFAULT_FILENAME);
|
||||
return UseFilePath(path: rootedPath, name: "ps-rule.yaml") ??
|
||||
UseFilePath(path: rootedPath, name: "ps-rule.yml") ??
|
||||
UseFilePath(path: rootedPath, name: "psrule.yaml") ??
|
||||
UseFilePath(path: rootedPath, name: "psrule.yml") ??
|
||||
Path.Combine(rootedPath, DEFAULT_FILENAME);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -421,5 +448,13 @@ namespace PSRule.Configuration
|
|||
var filePath = Path.Combine(path, name);
|
||||
return File.Exists(filePath) ? filePath : null;
|
||||
}
|
||||
|
||||
private string GetYaml()
|
||||
{
|
||||
var s = new SerializerBuilder()
|
||||
.WithNamingConvention(new CamelCaseNamingConvention())
|
||||
.Build();
|
||||
return s.Serialize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,26 @@
|
|||
</CustomEntries>
|
||||
</CustomControl>
|
||||
</Control>
|
||||
<Control>
|
||||
<Name>Option-Yaml</Name>
|
||||
<CustomControl>
|
||||
<CustomEntries>
|
||||
<CustomEntry>
|
||||
<CustomItem>
|
||||
<Text AssemblyName="PSRule" BaseName="PSRule.Resources.ViewStrings" ResourceId="OptionsComment"/>
|
||||
<NewLine />
|
||||
<Frame>
|
||||
<CustomItem>
|
||||
<ExpressionBinding>
|
||||
<ScriptBlock>$_.ToYaml();</ScriptBlock>
|
||||
</ExpressionBinding>
|
||||
</CustomItem>
|
||||
</Frame>
|
||||
</CustomItem>
|
||||
</CustomEntry>
|
||||
</CustomEntries>
|
||||
</CustomControl>
|
||||
</Control>
|
||||
</Controls>
|
||||
<ViewDefinitions>
|
||||
<View>
|
||||
|
@ -329,5 +349,22 @@
|
|||
</TableRowEntries>
|
||||
</TableControl>
|
||||
</View>
|
||||
<View>
|
||||
<Name>PSRule.Configuration.PSRuleOption</Name>
|
||||
<ViewSelectedBy>
|
||||
<TypeName>PSRule.Configuration.PSRuleOption</TypeName>
|
||||
</ViewSelectedBy>
|
||||
<CustomControl>
|
||||
<CustomEntries>
|
||||
<CustomEntry>
|
||||
<CustomItem>
|
||||
<ExpressionBinding>
|
||||
<CustomControlName>Option-Yaml</CustomControlName>
|
||||
</ExpressionBinding>
|
||||
</CustomItem>
|
||||
</CustomEntry>
|
||||
</CustomEntries>
|
||||
</CustomControl>
|
||||
</View>
|
||||
</ViewDefinitions>
|
||||
</Configuration>
|
||||
|
|
|
@ -123,6 +123,15 @@ namespace PSRule.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to # Source: {0}.
|
||||
/// </summary>
|
||||
internal static string OptionsSourceComment {
|
||||
get {
|
||||
return ResourceManager.GetString("OptionsSourceComment", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to [FAIL] -- {0}:: Reported for '{1}'.
|
||||
/// </summary>
|
||||
|
|
|
@ -143,6 +143,9 @@
|
|||
<value>Options file does not exist.</value>
|
||||
<comment>Occurs when explicit path to a YAML file is specified and doesn't exist.</comment>
|
||||
</data>
|
||||
<data name="OptionsSourceComment" xml:space="preserve">
|
||||
<value># Source: {0}</value>
|
||||
</data>
|
||||
<data name="OutcomeRuleFail" xml:space="preserve">
|
||||
<value>[FAIL] -- {0}:: Reported for '{1}'</value>
|
||||
</data>
|
||||
|
|
|
@ -105,6 +105,15 @@ namespace PSRule.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to # PSRule options.
|
||||
/// </summary>
|
||||
internal static string OptionsComment {
|
||||
get {
|
||||
return ResourceManager.GetString("OptionsComment", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Outcome.
|
||||
/// </summary>
|
||||
|
|
|
@ -132,6 +132,9 @@
|
|||
<data name="Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="OptionsComment" xml:space="preserve">
|
||||
<value># PSRule options</value>
|
||||
</data>
|
||||
<data name="Outcome" xml:space="preserve">
|
||||
<value>Outcome</value>
|
||||
</data>
|
||||
|
|
|
@ -30,6 +30,30 @@ $Null = New-Item -Path $outputPath -ItemType Directory -Force;
|
|||
Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' {
|
||||
$emptyOptionsFilePath = (Join-Path -Path $here -ChildPath 'PSRule.Tests4.yml');
|
||||
|
||||
Context 'Use -Path' {
|
||||
It 'With file' {
|
||||
$filePath = Join-Path -Path $outputPath -ChildPath 'new.file/ps-rule.yaml';
|
||||
Set-PSRuleOption -Path $filePath -Force;
|
||||
{ New-PSRuleOption -Path $filePath -ErrorAction Stop } | Should -Not -Throw;
|
||||
}
|
||||
|
||||
It 'With directory' {
|
||||
$filePath = Join-Path -Path $outputPath -ChildPath 'new.file';
|
||||
Set-PSRuleOption -Path $filePath -Force;
|
||||
{ New-PSRuleOption -Path $filePath -ErrorAction Stop } | Should -Not -Throw;
|
||||
}
|
||||
|
||||
It 'With missing file' {
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'new-not-a-file.yaml');
|
||||
{ New-PSRuleOption -Path $filePath -ErrorAction Stop } | Should -Throw;
|
||||
}
|
||||
|
||||
It 'With missing directory' {
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'new-dir/ps-rule.yaml');
|
||||
{ New-PSRuleOption -Path $filePath -ErrorAction Stop } | Should -Throw;
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Read Baseline.RuleName' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption;
|
||||
|
@ -493,19 +517,19 @@ Describe 'Set-PSRuleOption' -Tag 'Option','Set-PSRuleOption' {
|
|||
|
||||
Context 'Use -Path' {
|
||||
It 'With missing file' {
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'not-a-file.yml');
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'set-not-a-file.yml');
|
||||
{ Set-PSRuleOption -Path $filePath -ErrorAction Stop } | Should -Not -Throw;
|
||||
Test-Path -Path $filePath | Should -Be $True;
|
||||
}
|
||||
|
||||
It 'With missing directory' {
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'dir/ps-rule.yaml');
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'set-dir/ps-rule.yaml');
|
||||
{ Set-PSRuleOption -Path $filePath -ErrorAction Stop } | Should -Throw -ErrorId 'PSRule.PSRuleOption.ParentPathNotFound';
|
||||
Test-Path -Path $filePath | Should -Be $False;
|
||||
}
|
||||
|
||||
It 'With missing directory with -Force' {
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'dir/ps-rule.yaml');
|
||||
$filePath = (Join-Path -Path $outputPath -ChildPath 'set-dir/ps-rule.yaml');
|
||||
Set-PSRuleOption -Path $filePath -Force;
|
||||
Test-Path -Path $filePath | Should -Be $True;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче