Fix YAML options discovery and display #232 #233 (#234)

This commit is contained in:
Bernie White 2019-07-03 21:29:41 +12:00 коммит произвёл GitHub
Родитель f290f051cc
Коммит 0d57f6da36
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 149 добавлений и 26 удалений

Просмотреть файл

@ -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>

9
src/PSRule/Resources/PSRuleResources.Designer.cs сгенерированный
Просмотреть файл

@ -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 &apos;{1}&apos;.
/// </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>

9
src/PSRule/Resources/ViewStrings.Designer.cs сгенерированный
Просмотреть файл

@ -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;
}