зеркало из https://github.com/microsoft/PSRule.git
Родитель
29e96c8c63
Коммит
3b6be55376
|
@ -292,6 +292,7 @@ The following conceptual topics exist in the `PSRule` module:
|
|||
- [Configuration](https://aka.ms/ps-rule/options#configuration)
|
||||
- [Convention.Include](https://aka.ms/ps-rule/options#conventioninclude)
|
||||
- [Execution.AliasReference](https://aka.ms/ps-rule/options#executionaliasreference)
|
||||
- [Execution.Break](https://aka.ms/ps-rule/options#executionbreak)
|
||||
- [Execution.DuplicateResourceId](https://aka.ms/ps-rule/options#executionduplicateresourceid)
|
||||
- [Execution.HashAlgorithm](https://aka.ms/ps-rule/options#executionhashalgorithm)
|
||||
- [Execution.LanguageMode](https://aka.ms/ps-rule/options#executionlanguagemode)
|
||||
|
@ -303,6 +304,7 @@ The following conceptual topics exist in the `PSRule` module:
|
|||
- [Execution.UnprocessedObject](https://aka.ms/ps-rule/options#executionunprocessedobject)
|
||||
- [Include.Module](https://aka.ms/ps-rule/options#includemodule)
|
||||
- [Include.Path](https://aka.ms/ps-rule/options#includepath)
|
||||
- [Input.FileObjects](https://aka.ms/ps-rule/options#inputfileobjects)
|
||||
- [Input.Format](https://aka.ms/ps-rule/options#inputformat)
|
||||
- [Input.IgnoreGitPath](https://aka.ms/ps-rule/options#inputignoregitpath)
|
||||
- [Input.IgnoreObjectSource](https://aka.ms/ps-rule/options#inputignoreobjectsource)
|
||||
|
|
|
@ -29,6 +29,13 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers
|
|||
|
||||
What's changed since pre-release v3.0.0-B0203:
|
||||
|
||||
- New features:
|
||||
- Added option to configure the severity level that PSRule will break the pipeline at by @BernieWhite.
|
||||
[#1508](https://github.com/microsoft/PSRule/issues/1508)
|
||||
- Previously only rules with the severity level `Error` would break the pipeline.
|
||||
- With this update rules with the severity level `Error` that fail will break the pipeline by default.
|
||||
- The `Execution.Break` option can be set to `Never`, `OnError`, `OnWarning`, or `OnInformation`.
|
||||
- If a rule fails with a severity level equal or higher than the configured level the pipeline will break.
|
||||
- Engineering:
|
||||
- Bump xunit to v2.8.1.
|
||||
[#1840](https://github.com/microsoft/PSRule/pull/1840)
|
||||
|
|
|
@ -16,6 +16,7 @@ The following workspace options are available for use:
|
|||
- [Baseline.Group](#baselinegroup)
|
||||
- [Convention.Include](#conventioninclude)
|
||||
- [Execution.AliasReference](#executionaliasreference)
|
||||
- [Execution.Break](#executionbreak)
|
||||
- [Execution.DuplicateResourceId](#executionduplicateresourceid)
|
||||
- [Execution.HashAlgorithm](#executionhashalgorithm)
|
||||
- [Execution.LanguageMode](#executionlanguagemode)
|
||||
|
@ -791,6 +792,68 @@ variables:
|
|||
value: Error
|
||||
```
|
||||
|
||||
### Execution.Break
|
||||
|
||||
:octicons-milestone-24: v3.0.0
|
||||
|
||||
Determines the minimum rule severity level that breaks the pipeline.
|
||||
By default, the pipeline will break if a rule of error severity level fails.
|
||||
|
||||
For this to take effect the rule must execute successfully and return a failure.
|
||||
This does not affect the pipeline if other errors or exceptions occurs.
|
||||
|
||||
The following preferences are available:
|
||||
|
||||
- `None` (0) - No preference.
|
||||
Inherits the default of `Error`.
|
||||
- `Never` = (1) - Never break the pipeline if a rule fails regardless of level.
|
||||
The pipeline will still break if other errors occur.
|
||||
- `OnError` = (2) - Break the pipeline if a rule of error severity level fails.
|
||||
This is the default.
|
||||
- `OnWarning` = (3) - Break the pipeline if a rule of warning or error severity level fails.
|
||||
- `OnInformation` = (4) - Break the pipeline if a rule of information, warning, or error severity level fails.
|
||||
|
||||
This option can be specified using:
|
||||
|
||||
```powershell
|
||||
# PowerShell: Using the Break parameter
|
||||
$option = New-PSRuleOption -ExecutionBreak 'Never';
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell: Using the Execution.Break hashtable key
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.Break' = 'Never' };
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell: Using the ExecutionBreak parameter to set YAML
|
||||
Set-PSRuleOption -ExecutionBreak 'Never';
|
||||
```
|
||||
|
||||
```yaml
|
||||
# YAML: Using the execution/break property
|
||||
execution:
|
||||
break: Never
|
||||
```
|
||||
|
||||
```bash
|
||||
# Bash: Using environment variable
|
||||
export PSRULE_EXECUTION_BREAK=Never
|
||||
```
|
||||
|
||||
```yaml
|
||||
# GitHub Actions: Using environment variable
|
||||
env:
|
||||
PSRULE_EXECUTION_BREAK: Never
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Azure Pipelines: Using environment variable
|
||||
variables:
|
||||
- name: PSRULE_EXECUTION_BREAK
|
||||
value: Never
|
||||
```
|
||||
|
||||
### Execution.DuplicateResourceId
|
||||
|
||||
:octicons-milestone-24: v2.4.0
|
||||
|
@ -1517,6 +1580,8 @@ variables:
|
|||
|
||||
### Input.FileObjects
|
||||
|
||||
:octicons-milestone-24: v3.0.0
|
||||
|
||||
Determines if file objects are processed by rules.
|
||||
This option is for backwards compatibility with PSRule v2.x in cases where file objects are used as input.
|
||||
|
||||
|
|
|
@ -356,6 +356,19 @@
|
|||
"description": "Options that affect execution.",
|
||||
"markdownDescription": "Options that affect execution. [See help](https://aka.ms/ps-rule/options)",
|
||||
"properties": {
|
||||
"break": {
|
||||
"type": "string",
|
||||
"title": "Break",
|
||||
"description": "Determines the minimum rule severity level that breaks the pipeline. By default, the pipeline will break if a rule of error severity fails.",
|
||||
"markdownDescription": "Determines the minimum rule severity level that breaks the pipeline. By default, the pipeline will break if a rule of error severity fails.\n\n[See help](https://microsoft.github.io/PSRule/v3/concepts/PSRule/en-US/about_PSRule_Options/#executionbreak)",
|
||||
"enum": [
|
||||
"Never",
|
||||
"OnError",
|
||||
"OnWarning",
|
||||
"OnInformation"
|
||||
],
|
||||
"default": "OnError"
|
||||
},
|
||||
"duplicateResourceId": {
|
||||
"type": "string",
|
||||
"title": "Duplicate resource identifiers",
|
||||
|
|
|
@ -53,7 +53,7 @@ public sealed class RunCommand
|
|||
pipeline.Begin();
|
||||
pipeline.Process(null);
|
||||
pipeline.End();
|
||||
if (pipeline.Result.HadFailures)
|
||||
if (pipeline.Result.ShouldBreakFromFailure)
|
||||
exitCode = ERROR_BREAK_ON_FAILURE;
|
||||
}
|
||||
return clientContext.Host.HadErrors || pipeline == null ? ERROR_GENERIC : exitCode;
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
namespace PSRule.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Determine the rule severity level at which to break the pipeline.
|
||||
/// </summary>
|
||||
public enum BreakLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// No preference.
|
||||
/// Inherits the default of <c>OnError</c>.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Continue even if a rule fails regardless of rule severity.
|
||||
/// </summary>
|
||||
Never = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Only break on error.
|
||||
/// </summary>
|
||||
OnError = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Break if any rule of warning or error severity fails.
|
||||
/// </summary>
|
||||
OnWarning = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Break if any rule fails.
|
||||
/// </summary>
|
||||
OnInformation = 4
|
||||
}
|
|
@ -5,113 +5,6 @@ using System.ComponentModel;
|
|||
|
||||
namespace PSRule.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Options that configure the execution sandbox.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See <see href="https://aka.ms/ps-rule/options"/>.
|
||||
/// </remarks>
|
||||
public interface IExecutionOption : IOption
|
||||
{
|
||||
/// <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.
|
||||
/// 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.
|
||||
/// </summary>
|
||||
ExecutionActionPreference DuplicateResourceId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Configures the hashing algorithm used by the PSRule runtime.
|
||||
/// The default is <see cref="HashAlgorithm.SHA512"/>.
|
||||
/// </summary>
|
||||
HashAlgorithm HashAlgorithm { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The language mode to execute PowerShell code with.
|
||||
/// The default is <see cref="LanguageMode.FullLanguage"/>.
|
||||
/// </summary>
|
||||
LanguageMode LanguageMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how the initial session state for executing PowerShell code is created.
|
||||
/// The default is <see cref="SessionState.BuiltIn"/>.
|
||||
/// </summary>
|
||||
SessionState InitialSessionState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Configures where to allow PowerShell language features (such as rules and conventions) to run from.
|
||||
/// The default is <see cref="RestrictScriptSource.Unrestricted"/>.
|
||||
/// </summary>
|
||||
RestrictScriptSource RestrictScriptSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle expired suppression groups.
|
||||
/// Regardless of the value, an expired suppression group will be ignored.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference SuppressionGroupExpired { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle rules that are excluded.
|
||||
/// By default, excluded rules do not generated any output.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Warn, a warning is generated.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// </summary>
|
||||
ExecutionActionPreference RuleExcluded { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle rules that are suppressed.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference RuleSuppressed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle when an alias to a resource is used.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference AliasReference { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle rules that generate inconclusive results.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference RuleInconclusive { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to report when an invariant culture is used.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference InvariantCulture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to report objects that are not processed by any rule.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference UnprocessedObject { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options that configure the execution sandbox.
|
||||
/// </summary>
|
||||
|
@ -120,6 +13,7 @@ public interface IExecutionOption : IOption
|
|||
/// </remarks>
|
||||
public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOption
|
||||
{
|
||||
private const BreakLevel DEFAULT_BREAK = BreakLevel.OnError;
|
||||
private const LanguageMode DEFAULT_LANGUAGEMODE = Options.LanguageMode.FullLanguage;
|
||||
private const ExecutionActionPreference DEFAULT_DUPLICATERESOURCEID = ExecutionActionPreference.Error;
|
||||
private const SessionState DEFAULT_INITIALSESSIONSTATE = SessionState.BuiltIn;
|
||||
|
@ -135,6 +29,7 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
|
||||
internal static readonly ExecutionOption Default = new()
|
||||
{
|
||||
Break = DEFAULT_BREAK,
|
||||
DuplicateResourceId = DEFAULT_DUPLICATERESOURCEID,
|
||||
HashAlgorithm = DEFAULT_HASHALGORITHM,
|
||||
LanguageMode = DEFAULT_LANGUAGEMODE,
|
||||
|
@ -154,6 +49,7 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
/// </summary>
|
||||
public ExecutionOption()
|
||||
{
|
||||
Break = null;
|
||||
DuplicateResourceId = null;
|
||||
HashAlgorithm = null;
|
||||
LanguageMode = null;
|
||||
|
@ -177,6 +73,7 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
if (option == null)
|
||||
return;
|
||||
|
||||
Break = option.Break;
|
||||
DuplicateResourceId = option.DuplicateResourceId;
|
||||
HashAlgorithm = option.HashAlgorithm;
|
||||
LanguageMode = option.LanguageMode;
|
||||
|
@ -201,6 +98,7 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
public bool Equals(ExecutionOption other)
|
||||
{
|
||||
return other != null &&
|
||||
Break == other.Break &&
|
||||
DuplicateResourceId == other.DuplicateResourceId &&
|
||||
HashAlgorithm == other.HashAlgorithm &&
|
||||
LanguageMode == other.LanguageMode &&
|
||||
|
@ -221,6 +119,7 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
unchecked // Overflow is fine
|
||||
{
|
||||
var hash = 17;
|
||||
hash = hash * 23 + (Break.HasValue ? Break.Value.GetHashCode() : 0);
|
||||
hash = hash * 23 + (DuplicateResourceId.HasValue ? DuplicateResourceId.Value.GetHashCode() : 0);
|
||||
hash = hash * 23 + (HashAlgorithm.HasValue ? HashAlgorithm.Value.GetHashCode() : 0);
|
||||
hash = hash * 23 + (LanguageMode.HasValue ? LanguageMode.Value.GetHashCode() : 0);
|
||||
|
@ -245,6 +144,7 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
{
|
||||
var result = new ExecutionOption(o1)
|
||||
{
|
||||
Break = o1?.Break ?? o2?.Break,
|
||||
DuplicateResourceId = o1?.DuplicateResourceId ?? o2?.DuplicateResourceId,
|
||||
HashAlgorithm = o1?.HashAlgorithm ?? o2?.HashAlgorithm,
|
||||
LanguageMode = o1?.LanguageMode ?? o2?.LanguageMode,
|
||||
|
@ -261,6 +161,13 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the minimum rule severity level that breaks the pipeline.
|
||||
/// By default, the pipeline will break if a rule of error severity fails.
|
||||
/// </summary>
|
||||
[DefaultValue(null)]
|
||||
public BreakLevel? Break { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle duplicate resources identifiers during execution.
|
||||
/// Regardless of the value, only the first resource will be used.
|
||||
|
@ -371,6 +278,8 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
|
||||
#region IExecutionOption
|
||||
|
||||
BreakLevel IExecutionOption.Break => Break ?? DEFAULT_BREAK;
|
||||
|
||||
ExecutionActionPreference IExecutionOption.DuplicateResourceId => DuplicateResourceId ?? DEFAULT_DUPLICATERESOURCEID;
|
||||
|
||||
HashAlgorithm IExecutionOption.HashAlgorithm => HashAlgorithm ?? DEFAULT_HASHALGORITHM;
|
||||
|
@ -402,6 +311,9 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
/// </summary>
|
||||
internal void Load()
|
||||
{
|
||||
if (Environment.TryEnum("PSRULE_EXECUTION_BREAK", out BreakLevel @break))
|
||||
Break = @break;
|
||||
|
||||
if (Environment.TryEnum("PSRULE_EXECUTION_HASHALGORITHM", out HashAlgorithm hashAlgorithm))
|
||||
HashAlgorithm = hashAlgorithm;
|
||||
|
||||
|
@ -444,6 +356,9 @@ public sealed class ExecutionOption : IEquatable<ExecutionOption>, IExecutionOpt
|
|||
/// </summary>
|
||||
internal void Load(Dictionary<string, object> index)
|
||||
{
|
||||
if (index.TryPopEnum("Execution.Break", out BreakLevel @break))
|
||||
Break = @break;
|
||||
|
||||
if (index.TryPopEnum("Execution.HashAlgorithm", out HashAlgorithm hashAlgorithm))
|
||||
HashAlgorithm = hashAlgorithm;
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
namespace PSRule.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Options that configure the execution sandbox.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See <see href="https://aka.ms/ps-rule/options"/>.
|
||||
/// </remarks>
|
||||
public interface IExecutionOption : IOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the minimum rule severity level that breaks the pipeline.
|
||||
/// By default, the pipeline will break if a rule of error severity fails.
|
||||
/// </summary>
|
||||
BreakLevel Break { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle duplicate resources identifiers during execution.
|
||||
/// Regardless of the value, only the first resource will be used.
|
||||
/// 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.
|
||||
/// </summary>
|
||||
ExecutionActionPreference DuplicateResourceId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Configures the hashing algorithm used by the PSRule runtime.
|
||||
/// The default is <see cref="HashAlgorithm.SHA512"/>.
|
||||
/// </summary>
|
||||
HashAlgorithm HashAlgorithm { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The language mode to execute PowerShell code with.
|
||||
/// The default is <see cref="LanguageMode.FullLanguage"/>.
|
||||
/// </summary>
|
||||
LanguageMode LanguageMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how the initial session state for executing PowerShell code is created.
|
||||
/// The default is <see cref="SessionState.BuiltIn"/>.
|
||||
/// </summary>
|
||||
SessionState InitialSessionState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Configures where to allow PowerShell language features (such as rules and conventions) to run from.
|
||||
/// The default is <see cref="RestrictScriptSource.Unrestricted"/>.
|
||||
/// </summary>
|
||||
RestrictScriptSource RestrictScriptSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle expired suppression groups.
|
||||
/// Regardless of the value, an expired suppression group will be ignored.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference SuppressionGroupExpired { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle rules that are excluded.
|
||||
/// By default, excluded rules do not generated any output.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Warn, a warning is generated.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// </summary>
|
||||
ExecutionActionPreference RuleExcluded { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle rules that are suppressed.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference RuleSuppressed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle when an alias to a resource is used.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference AliasReference { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to handle rules that generate inconclusive results.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference RuleInconclusive { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to report when an invariant culture is used.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference InvariantCulture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines how to report objects that are not processed by any rule.
|
||||
/// By default, a warning is generated.
|
||||
/// When set to Error, an error is thrown.
|
||||
/// When set to Debug, a message is written to the debug log.
|
||||
/// When set to Ignore, no output will be displayed.
|
||||
/// </summary>
|
||||
ExecutionActionPreference UnprocessedObject { get; }
|
||||
}
|
|
@ -1163,6 +1163,10 @@ function New-PSRuleOption {
|
|||
[Alias('ConventionInclude')]
|
||||
[String[]]$Convention,
|
||||
|
||||
# Sets the Execution.Break option
|
||||
[Parameter(Mandatory = $False)]
|
||||
[PSRule.Options.BreakLevel]$ExecutionBreak = [PSRule.Options.BreakLevel]::OnError,
|
||||
|
||||
# Sets the Execution.DuplicateResourceId option
|
||||
[Parameter(Mandatory = $False)]
|
||||
[Alias('ExecutionDuplicateResourceId')]
|
||||
|
@ -1476,6 +1480,10 @@ function Set-PSRuleOption {
|
|||
[Alias('ConventionInclude')]
|
||||
[String[]]$Convention,
|
||||
|
||||
# Sets the Execution.Break option
|
||||
[Parameter(Mandatory = $False)]
|
||||
[PSRule.Options.BreakLevel]$ExecutionBreak = [PSRule.Options.BreakLevel]::OnError,
|
||||
|
||||
# Sets the Execution.DuplicateResourceId option
|
||||
[Parameter(Mandatory = $False)]
|
||||
[Alias('ExecutionDuplicateResourceId')]
|
||||
|
@ -2236,6 +2244,10 @@ function SetOptions {
|
|||
[Alias('ConventionInclude')]
|
||||
[String[]]$Convention,
|
||||
|
||||
# Sets the Execution.Break option
|
||||
[Parameter(Mandatory = $False)]
|
||||
[PSRule.Options.BreakLevel]$ExecutionBreak = [PSRule.Options.BreakLevel]::OnError,
|
||||
|
||||
# Sets the Execution.DuplicateResourceId option
|
||||
[Parameter(Mandatory = $False)]
|
||||
[Alias('ExecutionDuplicateResourceId')]
|
||||
|
@ -2461,6 +2473,11 @@ function SetOptions {
|
|||
$Option.Convention.Include = $Convention;
|
||||
}
|
||||
|
||||
# Sets option Execution.Break
|
||||
if ($PSBoundParameters.ContainsKey('ExecutionBreak')) {
|
||||
$Option.Execution.Break = $ExecutionBreak;
|
||||
}
|
||||
|
||||
# Sets option Execution.DuplicateResourceId
|
||||
if ($PSBoundParameters.ContainsKey('DuplicateResourceId')) {
|
||||
$Option.Execution.DuplicateResourceId = $DuplicateResourceId;
|
||||
|
|
|
@ -44,7 +44,7 @@ internal sealed class AssertPipelineBuilder : InvokePipelineBuilderBase
|
|||
_ResultVariableName = resultVariableName;
|
||||
_HostContext = hostContext;
|
||||
if (!string.IsNullOrEmpty(resultVariableName))
|
||||
_Results = new List<RuleRecord>();
|
||||
_Results = [];
|
||||
|
||||
_Formatter = GetFormatter(style, source, inner, option);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ internal sealed class AssertPipelineBuilder : InvokePipelineBuilderBase
|
|||
return new VisualStudioCodeFormatter(source, inner, option);
|
||||
|
||||
return style == OutputStyle.Plain ?
|
||||
(IAssertFormatter)new PlainFormatter(source, inner, option) :
|
||||
new PlainFormatter(source, inner, option) :
|
||||
new ClientFormatter(source, inner, option);
|
||||
}
|
||||
|
||||
|
@ -100,10 +100,10 @@ internal sealed class AssertPipelineBuilder : InvokePipelineBuilderBase
|
|||
_Formatter.Begin();
|
||||
}
|
||||
|
||||
public override void End()
|
||||
public override void End(IPipelineResult result)
|
||||
{
|
||||
_Formatter.End(_TotalCount, _FailCount, _ErrorCount);
|
||||
base.End();
|
||||
base.End(result);
|
||||
try
|
||||
{
|
||||
if (_ErrorCount > 0)
|
||||
|
@ -115,7 +115,7 @@ internal sealed class AssertPipelineBuilder : InvokePipelineBuilderBase
|
|||
ErrorCategory.InvalidOperation,
|
||||
null));
|
||||
}
|
||||
else if (_FailCount > 0 && _Level == SeverityLevel.Error)
|
||||
else if (result.ShouldBreakFromFailure)
|
||||
{
|
||||
HadFailures = true;
|
||||
base.WriteError(new ErrorRecord(
|
||||
|
@ -133,13 +133,7 @@ internal sealed class AssertPipelineBuilder : InvokePipelineBuilderBase
|
|||
ErrorCategory.InvalidOperation,
|
||||
null));
|
||||
}
|
||||
if (_FailCount > 0 && _Level == SeverityLevel.Warning)
|
||||
{
|
||||
HadFailures = true;
|
||||
base.WriteWarning(PSRuleResources.RuleFailPipelineException);
|
||||
}
|
||||
|
||||
if (_FailCount > 0 && _Level == SeverityLevel.Information)
|
||||
else if (_FailCount > 0)
|
||||
{
|
||||
HadFailures = true;
|
||||
base.WriteHost(new HostInformationMessage() { Message = PSRuleResources.RuleFailPipelineException });
|
||||
|
@ -150,7 +144,7 @@ internal sealed class AssertPipelineBuilder : InvokePipelineBuilderBase
|
|||
}
|
||||
finally
|
||||
{
|
||||
_InnerWriter?.End();
|
||||
_InnerWriter?.End(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Definitions.Rules;
|
||||
using PSRule.Options;
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
internal sealed class DefaultPipelineResult(IPipelineWriter writer, BreakLevel breakLevel) : IPipelineResult
|
||||
{
|
||||
private readonly IPipelineWriter _Writer = writer;
|
||||
private readonly BreakLevel _BreakLevel = breakLevel == BreakLevel.None ? ExecutionOption.Default.Break.Value : breakLevel;
|
||||
private bool _HadErrors;
|
||||
private bool _HadFailures;
|
||||
private SeverityLevel _WorstCase = SeverityLevel.None;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HadErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
return _HadErrors || (_Writer != null && _Writer.HadErrors);
|
||||
}
|
||||
set
|
||||
{
|
||||
_HadErrors = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HadFailures
|
||||
{
|
||||
get
|
||||
{
|
||||
return _HadFailures || (_Writer != null && _Writer.HadFailures);
|
||||
}
|
||||
set
|
||||
{
|
||||
_HadFailures = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool ShouldBreakFromFailure { get; private set; }
|
||||
|
||||
public void Fail(SeverityLevel level)
|
||||
{
|
||||
_WorstCase = _WorstCase.GetWorstCase(level);
|
||||
_HadFailures = true;
|
||||
|
||||
if (ShouldBreakFromFailure || _BreakLevel == BreakLevel.Never || _WorstCase == SeverityLevel.None)
|
||||
return;
|
||||
|
||||
if (_BreakLevel == BreakLevel.OnInformation && (_WorstCase == SeverityLevel.Information || _WorstCase == SeverityLevel.Warning || _WorstCase == SeverityLevel.Error))
|
||||
{
|
||||
ShouldBreakFromFailure = true;
|
||||
}
|
||||
else if (_BreakLevel == BreakLevel.OnWarning && (_WorstCase == SeverityLevel.Warning || _WorstCase == SeverityLevel.Error))
|
||||
{
|
||||
ShouldBreakFromFailure = true;
|
||||
}
|
||||
else if (_BreakLevel == BreakLevel.OnError && _WorstCase == SeverityLevel.Error)
|
||||
{
|
||||
ShouldBreakFromFailure = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -176,7 +176,7 @@ internal abstract class AssertFormatterBase : PipelineLoggerBase, IAssertFormatt
|
|||
public void End(int total, int fail, int error)
|
||||
{
|
||||
if (Option.Output.Footer.GetValueOrDefault(FooterFormat.Default) != FooterFormat.None)
|
||||
LineBreak();
|
||||
BreakIfUnbrokenInfo();
|
||||
|
||||
FooterRuleCount(total, fail, error);
|
||||
FooterRunInfo();
|
||||
|
|
|
@ -26,7 +26,7 @@ internal sealed class GetBaselinePipeline : RulePipeline
|
|||
public override void End()
|
||||
{
|
||||
Writer.WriteObject(HostHelper.GetBaseline(Source, Context).Where(Match), true);
|
||||
Writer.End();
|
||||
Writer.End(Result);
|
||||
}
|
||||
|
||||
private bool Match(Baseline baseline)
|
||||
|
|
|
@ -24,6 +24,6 @@ internal sealed class GetRulePipeline : RulePipeline, IPipeline
|
|||
public override void End()
|
||||
{
|
||||
Writer.WriteObject(HostHelper.GetRule(Source, Context, _IncludeDependencies), true);
|
||||
Writer.End();
|
||||
Writer.End(Result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
/// <summary>
|
||||
/// An instance of a PSRule pipeline.
|
||||
/// </summary>
|
||||
public interface IPipeline : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the pipeline result.
|
||||
/// </summary>
|
||||
IPipelineResult Result { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the pipeline and results. Call this method once prior to calling Process.
|
||||
/// </summary>
|
||||
void Begin();
|
||||
|
||||
/// <summary>
|
||||
/// Process an object through the pipeline. Each object will be processed by rules that apply based on pre-conditions.
|
||||
/// </summary>
|
||||
/// <param name="sourceObject">The object to process.</param>
|
||||
void Process(PSObject sourceObject);
|
||||
|
||||
/// <summary>
|
||||
/// Clean up and flush pipeline results. Call this method once after processing any objects through the pipeline.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Matches PowerShell pipeline.")]
|
||||
void End();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
/// <summary>
|
||||
/// A result from the pipeline.
|
||||
/// </summary>
|
||||
public interface IPipelineResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if any errors were reported.
|
||||
/// </summary>
|
||||
public bool HadErrors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an failures were reported.
|
||||
/// </summary>
|
||||
public bool HadFailures { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the pipeline should break from rules that failed.
|
||||
/// </summary>
|
||||
public bool ShouldBreakFromFailure { get; }
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
/// <summary>
|
||||
/// An writer which receives output from PSRule.
|
||||
/// </summary>
|
||||
public interface IPipelineWriter : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if any errors were reported.
|
||||
/// </summary>
|
||||
bool HadErrors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if any failures were reported.
|
||||
/// </summary>
|
||||
bool HadFailures { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Write a verbose message.
|
||||
/// </summary>
|
||||
void WriteVerbose(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a verbose message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteVerbose();
|
||||
|
||||
/// <summary>
|
||||
/// Write a warning message.
|
||||
/// </summary>
|
||||
void WriteWarning(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a warning message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteWarning();
|
||||
|
||||
/// <summary>
|
||||
/// Write an error message.
|
||||
/// </summary>
|
||||
void WriteError(ErrorRecord errorRecord);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an error message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteError();
|
||||
|
||||
/// <summary>
|
||||
/// Write an informational message.
|
||||
/// </summary>
|
||||
void WriteInformation(InformationRecord informationRecord);
|
||||
|
||||
/// <summary>
|
||||
/// Write a message to the host process.
|
||||
/// </summary>
|
||||
void WriteHost(HostInformationMessage info);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an informational message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteInformation();
|
||||
|
||||
/// <summary>
|
||||
/// Write a debug message.
|
||||
/// </summary>
|
||||
void WriteDebug(string text, params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a debug message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteDebug();
|
||||
|
||||
/// <summary>
|
||||
/// Write an object to output.
|
||||
/// </summary>
|
||||
/// <param name="sendToPipeline">The object to write to the pipeline.</param>
|
||||
/// <param name="enumerateCollection">Determines when the object is enumerable if it should be enumerated as more then one object.</param>
|
||||
void WriteObject(object sendToPipeline, bool enumerateCollection);
|
||||
|
||||
/// <summary>
|
||||
/// Enter a logging scope.
|
||||
/// </summary>
|
||||
void EnterScope(string scopeName);
|
||||
|
||||
/// <summary>
|
||||
/// Exit a logging scope.
|
||||
/// </summary>
|
||||
void ExitScope();
|
||||
|
||||
/// <summary>
|
||||
/// Start and initialize the writer.
|
||||
/// </summary>
|
||||
void Begin();
|
||||
|
||||
/// <summary>
|
||||
/// Stop and finalized the writer.
|
||||
/// </summary>
|
||||
void End(IPipelineResult result);
|
||||
}
|
|
@ -35,13 +35,13 @@ internal sealed class InvokeRulePipeline : RulePipeline, IPipeline
|
|||
|
||||
_Outcome = outcome;
|
||||
_IsSummary = context.Option.Output.As.Value == ResultFormat.Summary;
|
||||
_Summary = _IsSummary ? new Dictionary<string, RuleSummaryRecord>() : null;
|
||||
_Summary = _IsSummary ? [] : null;
|
||||
var allRuleBlocks = _RuleGraph.GetAll();
|
||||
var resourceIndex = new ResourceIndex(allRuleBlocks);
|
||||
_SuppressionFilter = new SuppressionFilter(Context, context.Option.Suppression, resourceIndex);
|
||||
_SuppressionGroupFilter = new SuppressionFilter(Pipeline.SuppressionGroup, resourceIndex);
|
||||
|
||||
_Completed = new List<InvokeResult>();
|
||||
_Completed = [];
|
||||
}
|
||||
|
||||
public int RuleCount { get; private set; }
|
||||
|
@ -84,7 +84,7 @@ internal sealed class InvokeRulePipeline : RulePipeline, IPipeline
|
|||
if (_IsSummary)
|
||||
Writer.WriteObject(_Summary.Values.Where(r => _Outcome == RuleOutcome.All || (r.Outcome & _Outcome) > 0).ToArray(), true);
|
||||
|
||||
Writer.End();
|
||||
Writer.End(Result);
|
||||
}
|
||||
|
||||
private InvokeResult ProcessTargetObject(TargetObject targetObject)
|
||||
|
@ -148,7 +148,7 @@ internal sealed class InvokeRulePipeline : RulePipeline, IPipeline
|
|||
}
|
||||
else if (ruleRecord.Outcome == RuleOutcome.Fail)
|
||||
{
|
||||
Result.HadFailures = true;
|
||||
Result.Fail(ruleRecord.Level);
|
||||
ruleBlockTarget.Fail();
|
||||
Context.Fail();
|
||||
}
|
||||
|
|
|
@ -47,10 +47,10 @@ internal sealed class JobSummaryWriter : ResultOutputWriter<InvokeResult>
|
|||
base.Begin();
|
||||
}
|
||||
|
||||
public sealed override void End()
|
||||
public sealed override void End(IPipelineResult result)
|
||||
{
|
||||
Flush();
|
||||
base.End();
|
||||
base.End(result);
|
||||
}
|
||||
|
||||
#region Helper methods
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Management.Automation;
|
||||
using PSRule.Configuration;
|
||||
using PSRule.Data;
|
||||
using PSRule.Definitions;
|
||||
|
@ -189,88 +188,6 @@ public interface IPipelineBuilder
|
|||
IPipeline Build(IPipelineWriter writer = null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An instance of a PSRule pipeline.
|
||||
/// </summary>
|
||||
public interface IPipeline : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the pipeline result.
|
||||
/// </summary>
|
||||
IPipelineResult Result { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the pipeline and results. Call this method once prior to calling Process.
|
||||
/// </summary>
|
||||
void Begin();
|
||||
|
||||
/// <summary>
|
||||
/// Process an object through the pipeline. Each object will be processed by rules that apply based on pre-conditions.
|
||||
/// </summary>
|
||||
/// <param name="sourceObject">The object to process.</param>
|
||||
void Process(PSObject sourceObject);
|
||||
|
||||
/// <summary>
|
||||
/// Clean up and flush pipeline results. Call this method once after processing any objects through the pipeline.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Matches PowerShell pipeline.")]
|
||||
void End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A result from the pipeline.
|
||||
/// </summary>
|
||||
public interface IPipelineResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if any errors were reported.
|
||||
/// </summary>
|
||||
public bool HadErrors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an failures were reported.
|
||||
/// </summary>
|
||||
public bool HadFailures { get; }
|
||||
}
|
||||
|
||||
internal sealed class DefaultPipelineResult : IPipelineResult
|
||||
{
|
||||
private readonly IPipelineWriter _Writer;
|
||||
private bool _HadErrors;
|
||||
private bool _HadFailures;
|
||||
|
||||
public DefaultPipelineResult(IPipelineWriter writer)
|
||||
{
|
||||
_Writer = writer;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HadErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
return _HadErrors || (_Writer != null && _Writer.HadErrors);
|
||||
}
|
||||
set
|
||||
{
|
||||
_HadErrors = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HadFailures
|
||||
{
|
||||
get
|
||||
{
|
||||
return _HadFailures || (_Writer != null && _Writer.HadFailures);
|
||||
}
|
||||
set
|
||||
{
|
||||
_HadFailures = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class PipelineBuilderBase : IPipelineBuilder
|
||||
{
|
||||
private const string ENGINE_MODULE_NAME = "PSRule";
|
||||
|
@ -413,7 +330,7 @@ internal abstract class PipelineBuilderBase : IPipelineBuilder
|
|||
{
|
||||
var writer = PrepareWriter();
|
||||
writer.ErrorRequiredVersionMismatch(moduleName, moduleVersion, requiredVersion);
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, BreakLevel.None) { HadErrors = true });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -505,7 +422,7 @@ internal abstract class PipelineBuilderBase : IPipelineBuilder
|
|||
shouldProcess: HostContext.ShouldProcess,
|
||||
writeHost: writeHost
|
||||
)
|
||||
: (PipelineWriter)_Output;
|
||||
: _Output;
|
||||
}
|
||||
|
||||
protected static string[] GetCulture(string[] culture)
|
||||
|
@ -580,8 +497,7 @@ internal abstract class PipelineBuilderBase : IPipelineBuilder
|
|||
var ignoreGitPath = Option.Input.IgnoreGitPath ?? InputOption.Default.IgnoreGitPath.Value;
|
||||
var ignoreRepositoryCommon = Option.Input.IgnoreRepositoryCommon ?? InputOption.Default.IgnoreRepositoryCommon.Value;
|
||||
var builder = PathFilterBuilder.Create(basePath, Option.Input.PathIgnore, ignoreGitPath, ignoreRepositoryCommon);
|
||||
//if (Option.Input.Format == InputFormat.File)
|
||||
builder.UseGitIgnore();
|
||||
builder.UseGitIgnore();
|
||||
|
||||
_InputFilter = builder.Build();
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ internal abstract class PipelineLoggerBase : IPipelineWriter
|
|||
|
||||
}
|
||||
|
||||
public virtual void End()
|
||||
public virtual void End(IPipelineResult result)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -8,108 +8,10 @@ using PSRule.Rules;
|
|||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
/// <summary>
|
||||
/// An writer which recieves output from PSRule.
|
||||
/// </summary>
|
||||
public interface IPipelineWriter : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if any errors were reported.
|
||||
/// </summary>
|
||||
bool HadErrors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an failures were reported.
|
||||
/// </summary>
|
||||
bool HadFailures { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Write a verbose message.
|
||||
/// </summary>
|
||||
void WriteVerbose(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a verbose message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteVerbose();
|
||||
|
||||
/// <summary>
|
||||
/// Write a warning message.
|
||||
/// </summary>
|
||||
void WriteWarning(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a warning message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteWarning();
|
||||
|
||||
/// <summary>
|
||||
/// Write an error message.
|
||||
/// </summary>
|
||||
void WriteError(ErrorRecord errorRecord);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an error message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteError();
|
||||
|
||||
/// <summary>
|
||||
/// Write an informational message.
|
||||
/// </summary>
|
||||
void WriteInformation(InformationRecord informationRecord);
|
||||
|
||||
/// <summary>
|
||||
/// Write a message to the host process.
|
||||
/// </summary>
|
||||
void WriteHost(HostInformationMessage info);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if an informational message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteInformation();
|
||||
|
||||
/// <summary>
|
||||
/// Write a debug message.
|
||||
/// </summary>
|
||||
void WriteDebug(string text, params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a debug message should be written to output.
|
||||
/// </summary>
|
||||
bool ShouldWriteDebug();
|
||||
|
||||
/// <summary>
|
||||
/// Write an object to output.
|
||||
/// </summary>
|
||||
/// <param name="sendToPipeline">The object to write to the pipeline.</param>
|
||||
/// <param name="enumerateCollection">Determines when the object is enumerable if it should be enumerated as more then one object.</param>
|
||||
void WriteObject(object sendToPipeline, bool enumerateCollection);
|
||||
|
||||
/// <summary>
|
||||
/// Enter a logging scope.
|
||||
/// </summary>
|
||||
void EnterScope(string scopeName);
|
||||
|
||||
/// <summary>
|
||||
/// Exit a logging scope.
|
||||
/// </summary>
|
||||
void ExitScope();
|
||||
|
||||
/// <summary>
|
||||
/// Start and initialize the writer.
|
||||
/// </summary>
|
||||
void Begin();
|
||||
|
||||
/// <summary>
|
||||
/// Stop and finalized the writer.
|
||||
/// </summary>
|
||||
void End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A base class for writers.
|
||||
/// </summary>
|
||||
internal abstract class PipelineWriter : IPipelineWriter
|
||||
internal abstract class PipelineWriter(IPipelineWriter inner, PSRuleOption option, ShouldProcess shouldProcess) : IPipelineWriter
|
||||
{
|
||||
protected const string ErrorPreference = "ErrorActionPreference";
|
||||
protected const string WarningPreference = "WarningPreference";
|
||||
|
@ -117,22 +19,15 @@ internal abstract class PipelineWriter : IPipelineWriter
|
|||
protected const string InformationPreference = "InformationPreference";
|
||||
protected const string DebugPreference = "DebugPreference";
|
||||
|
||||
private readonly IPipelineWriter _Writer;
|
||||
private readonly ShouldProcess _ShouldProcess;
|
||||
private readonly IPipelineWriter _Writer = inner;
|
||||
private readonly ShouldProcess _ShouldProcess = shouldProcess;
|
||||
|
||||
protected readonly PSRuleOption Option;
|
||||
protected readonly PSRuleOption Option = option;
|
||||
|
||||
private bool _IsDisposed;
|
||||
private bool _HadErrors;
|
||||
private bool _HadFailures;
|
||||
|
||||
protected PipelineWriter(IPipelineWriter inner, PSRuleOption option, ShouldProcess shouldProcess)
|
||||
{
|
||||
_Writer = inner;
|
||||
_ShouldProcess = shouldProcess;
|
||||
Option = option;
|
||||
}
|
||||
|
||||
bool IPipelineWriter.HadErrors => HadErrors;
|
||||
|
||||
bool IPipelineWriter.HadFailures => HadFailures;
|
||||
|
@ -182,12 +77,12 @@ internal abstract class PipelineWriter : IPipelineWriter
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void End()
|
||||
public virtual void End(IPipelineResult result)
|
||||
{
|
||||
if (_Writer == null)
|
||||
return;
|
||||
|
||||
_Writer.End();
|
||||
_Writer.End(result);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -363,98 +258,8 @@ internal abstract class PipelineWriter : IPipelineWriter
|
|||
/// <summary>
|
||||
/// Get the value of a preference variable.
|
||||
/// </summary>
|
||||
protected static ActionPreference GetPreferenceVariable(System.Management.Automation.SessionState sessionState, string variableName)
|
||||
protected static ActionPreference GetPreferenceVariable(SessionState sessionState, string variableName)
|
||||
{
|
||||
return (ActionPreference)sessionState.PSVariable.GetValue(variableName);
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class ResultOutputWriter<T> : PipelineWriter
|
||||
{
|
||||
private readonly List<T> _Result;
|
||||
|
||||
protected ResultOutputWriter(IPipelineWriter inner, PSRuleOption option, ShouldProcess shouldProcess)
|
||||
: base(inner, option, shouldProcess)
|
||||
{
|
||||
_Result = new List<T>();
|
||||
}
|
||||
|
||||
public override void WriteObject(object sendToPipeline, bool enumerateCollection)
|
||||
{
|
||||
if (sendToPipeline is InvokeResult && Option.Output.As == ResultFormat.Summary)
|
||||
{
|
||||
base.WriteObject(sendToPipeline, enumerateCollection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendToPipeline is InvokeResult result)
|
||||
{
|
||||
Add(typeof(T) == typeof(RuleRecord) ? result.AsRecord() : result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(sendToPipeline);
|
||||
}
|
||||
base.WriteObject(sendToPipeline, enumerateCollection);
|
||||
}
|
||||
|
||||
protected void Add(object o)
|
||||
{
|
||||
if (o is T[] collection)
|
||||
_Result.AddRange(collection);
|
||||
else if (o is T item)
|
||||
_Result.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear any buffers from the writer.
|
||||
/// </summary>
|
||||
protected virtual void Flush() { }
|
||||
|
||||
protected T[] GetResults()
|
||||
{
|
||||
return _Result.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class SerializationOutputWriter<T> : ResultOutputWriter<T>
|
||||
{
|
||||
protected SerializationOutputWriter(IPipelineWriter inner, PSRuleOption option, ShouldProcess shouldProcess)
|
||||
: base(inner, option, shouldProcess) { }
|
||||
|
||||
public sealed override void End()
|
||||
{
|
||||
var results = GetResults();
|
||||
base.WriteObject(Serialize(results), false);
|
||||
ProcessError(results);
|
||||
Flush();
|
||||
base.End();
|
||||
}
|
||||
|
||||
public override void WriteObject(object sendToPipeline, bool enumerateCollection)
|
||||
{
|
||||
if (sendToPipeline is InvokeResult && Option.Output.As == ResultFormat.Summary)
|
||||
{
|
||||
base.WriteObject(sendToPipeline, enumerateCollection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendToPipeline is InvokeResult result)
|
||||
{
|
||||
Add(result.AsRecord());
|
||||
return;
|
||||
}
|
||||
Add(sendToPipeline);
|
||||
}
|
||||
|
||||
protected abstract string Serialize(T[] o);
|
||||
|
||||
private void ProcessError(T[] results)
|
||||
{
|
||||
for (var i = 0; i < results.Length; i++)
|
||||
{
|
||||
if (results[i] is RuleRecord record)
|
||||
WriteErrorInfo(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Configuration;
|
||||
using PSRule.Rules;
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
internal abstract class ResultOutputWriter<T> : PipelineWriter
|
||||
{
|
||||
private readonly List<T> _Result;
|
||||
|
||||
protected ResultOutputWriter(IPipelineWriter inner, PSRuleOption option, ShouldProcess shouldProcess)
|
||||
: base(inner, option, shouldProcess)
|
||||
{
|
||||
_Result = new List<T>();
|
||||
}
|
||||
|
||||
public override void WriteObject(object sendToPipeline, bool enumerateCollection)
|
||||
{
|
||||
if (sendToPipeline is InvokeResult && Option.Output.As == ResultFormat.Summary)
|
||||
{
|
||||
base.WriteObject(sendToPipeline, enumerateCollection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendToPipeline is InvokeResult result)
|
||||
{
|
||||
Add(typeof(T) == typeof(RuleRecord) ? result.AsRecord() : result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(sendToPipeline);
|
||||
}
|
||||
base.WriteObject(sendToPipeline, enumerateCollection);
|
||||
}
|
||||
|
||||
protected void Add(object o)
|
||||
{
|
||||
if (o is T[] collection)
|
||||
_Result.AddRange(collection);
|
||||
else if (o is T item)
|
||||
_Result.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear any buffers from the writer.
|
||||
/// </summary>
|
||||
protected virtual void Flush() { }
|
||||
|
||||
protected T[] GetResults()
|
||||
{
|
||||
return _Result.ToArray();
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using System.Management.Automation;
|
||||
using PSRule.Options;
|
||||
using PSRule.Runtime;
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
@ -19,7 +20,7 @@ internal abstract class RulePipeline : IPipeline
|
|||
|
||||
protected RulePipeline(PipelineContext context, Source[] source, PipelineInputStream reader, IPipelineWriter writer)
|
||||
{
|
||||
Result = new DefaultPipelineResult(writer);
|
||||
Result = new DefaultPipelineResult(writer, context.Option.Execution.Break.GetValueOrDefault(ExecutionOption.Default.Break.Value));
|
||||
Pipeline = context;
|
||||
Context = new RunspaceContext(Pipeline, writer);
|
||||
Source = source;
|
||||
|
@ -55,7 +56,7 @@ internal abstract class RulePipeline : IPipeline
|
|||
/// <inheritdoc/>
|
||||
public virtual void End()
|
||||
{
|
||||
Writer.End();
|
||||
Writer.End(Result);
|
||||
}
|
||||
|
||||
#endregion IPipeline
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Configuration;
|
||||
using PSRule.Rules;
|
||||
|
||||
namespace PSRule.Pipeline;
|
||||
|
||||
internal abstract class SerializationOutputWriter<T> : ResultOutputWriter<T>
|
||||
{
|
||||
protected SerializationOutputWriter(IPipelineWriter inner, PSRuleOption option, ShouldProcess shouldProcess)
|
||||
: base(inner, option, shouldProcess) { }
|
||||
|
||||
public sealed override void End(IPipelineResult result)
|
||||
{
|
||||
var results = GetResults();
|
||||
base.WriteObject(Serialize(results), false);
|
||||
ProcessError(results);
|
||||
Flush();
|
||||
base.End(result);
|
||||
}
|
||||
|
||||
public override void WriteObject(object sendToPipeline, bool enumerateCollection)
|
||||
{
|
||||
if (sendToPipeline is InvokeResult && Option.Output.As == ResultFormat.Summary)
|
||||
{
|
||||
base.WriteObject(sendToPipeline, enumerateCollection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendToPipeline is InvokeResult result)
|
||||
{
|
||||
Add(result.AsRecord());
|
||||
return;
|
||||
}
|
||||
Add(sendToPipeline);
|
||||
}
|
||||
|
||||
protected abstract string Serialize(T[] o);
|
||||
|
||||
private void ProcessError(T[] results)
|
||||
{
|
||||
for (var i = 0; i < results.Length; i++)
|
||||
{
|
||||
if (results[i] is RuleRecord record)
|
||||
WriteErrorInfo(record);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,12 +21,13 @@ public sealed class AssertFormatterTests
|
|||
{
|
||||
var option = GetOption();
|
||||
option.Output.Banner = BannerFormat.None;
|
||||
option.Output.Footer = FooterFormat.None;
|
||||
var writer = GetWriter();
|
||||
|
||||
// Check output is empty
|
||||
var formatter = new PlainFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal("", writer.Output);
|
||||
|
||||
// Check pass output
|
||||
|
@ -34,7 +35,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new PlainFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetPassResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [1/1]
|
||||
|
||||
[PASS] Test
|
||||
|
@ -45,7 +46,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new PlainFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -59,7 +60,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new PlainFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Warning));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -73,7 +74,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new PlainFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Information));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -88,12 +89,13 @@ public sealed class AssertFormatterTests
|
|||
{
|
||||
var option = GetOption();
|
||||
option.Output.Banner = BannerFormat.None;
|
||||
option.Output.Footer = FooterFormat.None;
|
||||
var writer = GetWriter();
|
||||
|
||||
// Check output is empty
|
||||
var formatter = new ClientFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal("", writer.Output);
|
||||
|
||||
// Check pass output
|
||||
|
@ -101,7 +103,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new ClientFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetPassResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [1/1]
|
||||
|
||||
[PASS] Test
|
||||
|
@ -112,7 +114,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new ClientFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -126,7 +128,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new ClientFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Warning));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -140,7 +142,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new ClientFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Information));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -155,12 +157,13 @@ public sealed class AssertFormatterTests
|
|||
{
|
||||
var option = GetOption();
|
||||
option.Output.Banner = BannerFormat.None;
|
||||
option.Output.Footer = FooterFormat.None;
|
||||
var writer = GetWriter();
|
||||
|
||||
// Check output is empty
|
||||
var formatter = new AzurePipelinesFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal("", writer.Output);
|
||||
|
||||
// Check pass output
|
||||
|
@ -168,7 +171,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new AzurePipelinesFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetPassResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [1/1]
|
||||
|
||||
[PASS] Test
|
||||
|
@ -179,7 +182,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new AzurePipelinesFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -197,7 +200,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new AzurePipelinesFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Warning));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -215,7 +218,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new AzurePipelinesFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Information));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -230,12 +233,13 @@ public sealed class AssertFormatterTests
|
|||
{
|
||||
var option = GetOption();
|
||||
option.Output.Banner = BannerFormat.None;
|
||||
option.Output.Footer = FooterFormat.None;
|
||||
var writer = GetWriter();
|
||||
|
||||
// Check output is empty
|
||||
var formatter = new GitHubActionsFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal("", writer.Output);
|
||||
|
||||
// Check pass output
|
||||
|
@ -243,7 +247,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new GitHubActionsFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetPassResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [1/1]
|
||||
|
||||
[PASS] Test
|
||||
|
@ -254,7 +258,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new GitHubActionsFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -272,7 +276,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new GitHubActionsFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Warning));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -290,7 +294,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new GitHubActionsFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Information));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@" -> TestObject : TestType [0/2]
|
||||
|
||||
[FAIL] Test1
|
||||
|
@ -309,12 +313,13 @@ public sealed class AssertFormatterTests
|
|||
{
|
||||
var option = GetOption();
|
||||
option.Output.Banner = BannerFormat.None;
|
||||
option.Output.Footer = FooterFormat.None;
|
||||
var writer = GetWriter();
|
||||
|
||||
// Check output is empty
|
||||
var formatter = new VisualStudioCodeFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal("", writer.Output);
|
||||
|
||||
// Check pass output
|
||||
|
@ -322,7 +327,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new VisualStudioCodeFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetPassResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@"> TestObject : TestType [1/1]
|
||||
|
||||
PASS Test
|
||||
|
@ -333,7 +338,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new VisualStudioCodeFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult());
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@"> TestObject : TestType [0/2]
|
||||
|
||||
FAIL Test1
|
||||
|
@ -347,7 +352,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new VisualStudioCodeFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Warning));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@"> TestObject : TestType [0/2]
|
||||
|
||||
FAIL Test1
|
||||
|
@ -361,7 +366,7 @@ public sealed class AssertFormatterTests
|
|||
formatter = new VisualStudioCodeFormatter(null, writer, option);
|
||||
formatter.Begin();
|
||||
formatter.Result(GetFailResult(SeverityLevel.Information));
|
||||
formatter.End();
|
||||
formatter.End(0, 0, 0);
|
||||
Assert.Equal(@"> TestObject : TestType [0/2]
|
||||
|
||||
FAIL Test1
|
||||
|
|
|
@ -34,7 +34,7 @@ public sealed class OutputWriterTests
|
|||
var writer = new SarifOutputWriter(null, output, option, null);
|
||||
writer.Begin();
|
||||
writer.WriteObject(result, false);
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, Options.BreakLevel.None));
|
||||
|
||||
var actual = JsonConvert.DeserializeObject<JObject>(output.Output.OfType<string>().FirstOrDefault());
|
||||
Assert.NotNull(actual);
|
||||
|
@ -78,7 +78,7 @@ public sealed class OutputWriterTests
|
|||
var writer = new SarifOutputWriter(null, output, option, null);
|
||||
writer.Begin();
|
||||
writer.WriteObject(result, false);
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, Options.BreakLevel.None));
|
||||
|
||||
var actual = JsonConvert.DeserializeObject<JObject>(output.Output.OfType<string>().FirstOrDefault());
|
||||
Assert.NotNull(actual);
|
||||
|
@ -112,7 +112,7 @@ public sealed class OutputWriterTests
|
|||
var writer = new YamlOutputWriter(output, option, null);
|
||||
writer.Begin();
|
||||
writer.WriteObject(result, false);
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, Options.BreakLevel.None));
|
||||
|
||||
Assert.Equal(@"- detail:
|
||||
reason: []
|
||||
|
@ -210,7 +210,7 @@ public sealed class OutputWriterTests
|
|||
var writer = new JsonOutputWriter(output, option, null);
|
||||
writer.Begin();
|
||||
writer.WriteObject(result, false);
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, Options.BreakLevel.None));
|
||||
|
||||
Assert.Equal(@"[
|
||||
{
|
||||
|
@ -331,7 +331,7 @@ public sealed class OutputWriterTests
|
|||
var writer = new NUnit3OutputWriter(output, option, null);
|
||||
writer.Begin();
|
||||
writer.WriteObject(result, false);
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, Options.BreakLevel.None));
|
||||
|
||||
var s = output.Output.OfType<string>().FirstOrDefault();
|
||||
var doc = new XmlDocument();
|
||||
|
@ -357,7 +357,7 @@ public sealed class OutputWriterTests
|
|||
var writer = new CsvOutputWriter(output, option, null);
|
||||
writer.Begin();
|
||||
writer.WriteObject(result, false);
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, Options.BreakLevel.None));
|
||||
|
||||
var actual = output.Output.OfType<string>().FirstOrDefault();
|
||||
|
||||
|
@ -384,7 +384,7 @@ public sealed class OutputWriterTests
|
|||
writer.Begin();
|
||||
writer.WriteObject(result, false);
|
||||
context.RunTime.Stop();
|
||||
writer.End();
|
||||
writer.End(new DefaultPipelineResult(null, Options.BreakLevel.None));
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
using var reader = new StreamReader(stream);
|
||||
|
|
|
@ -635,6 +635,145 @@ Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' {
|
|||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.AliasReference' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
$option.Execution.AliasReference | Should -Be 'Warn';
|
||||
}
|
||||
|
||||
It 'from Hashtable' {
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.AliasReference' = 'error' };
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.AliasReference' = 'Error' };
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
}
|
||||
|
||||
It 'from YAML' {
|
||||
$option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml');
|
||||
$option.Execution.AliasReference | Should -Be 'Ignore';
|
||||
}
|
||||
|
||||
It 'from Environment' {
|
||||
try {
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_ALIASREFERENCE = 'error';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_ALIASREFERENCE = 'Error';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
|
||||
# With int
|
||||
$Env:PSRULE_EXECUTION_ALIASREFERENCE = '3';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
}
|
||||
finally {
|
||||
Remove-Item 'Env:PSRULE_EXECUTION_ALIASREFERENCE' -Force;
|
||||
}
|
||||
}
|
||||
|
||||
It 'from parameter' {
|
||||
$option = New-PSRuleOption -ExecutionAliasReference 'Error' -Path $emptyOptionsFilePath;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.Break' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
$option.Execution.Break | Should -Be 'OnError';
|
||||
}
|
||||
|
||||
It 'from Hashtable' {
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.Break' = 'never' };
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.Break' = 'Never' };
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
}
|
||||
|
||||
It 'from YAML' {
|
||||
$option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests16.yml');
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
}
|
||||
|
||||
It 'from Environment' {
|
||||
try {
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_BREAK = 'never';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
|
||||
$Env:PSRULE_EXECUTION_BREAK = 'never';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
|
||||
# With int
|
||||
$Env:PSRULE_EXECUTION_BREAK = '1';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
}
|
||||
finally {
|
||||
Remove-Item 'Env:PSRULE_EXECUTION_BREAK' -Force;
|
||||
}
|
||||
}
|
||||
|
||||
It 'from parameter' {
|
||||
$option = New-PSRuleOption -ExecutionBreak 'Never' -Path $emptyOptionsFilePath;
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.DuplicateResourceId' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Error'
|
||||
}
|
||||
|
||||
It 'from Hashtable' {
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.DuplicateResourceId' = 'warn' };
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.DuplicateResourceId' = 'Warn' };
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
|
||||
It 'from YAML' {
|
||||
$option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml');
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
|
||||
It 'from Environment' {
|
||||
try {
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_DUPLICATERESOURCEID = 'warn';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
|
||||
$Env:PSRULE_EXECUTION_DUPLICATERESOURCEID = 'Warn';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
|
||||
# With int
|
||||
$Env:PSRULE_EXECUTION_DUPLICATERESOURCEID = '2';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
finally {
|
||||
Remove-Item 'Env:PSRULE_EXECUTION_DUPLICATERESOURCEID' -Force;
|
||||
}
|
||||
}
|
||||
|
||||
It 'from parameter' {
|
||||
$option = New-PSRuleOption -DuplicateResourceId 'Warn' -Path $emptyOptionsFilePath;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.HashAlgorithm' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
|
@ -827,53 +966,6 @@ Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' {
|
|||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.AliasReference' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
$option.Execution.AliasReference | Should -Be 'Warn';
|
||||
}
|
||||
|
||||
It 'from Hashtable' {
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.AliasReference' = 'error' };
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.AliasReference' = 'Error' };
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
}
|
||||
|
||||
It 'from YAML' {
|
||||
$option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml');
|
||||
$option.Execution.AliasReference | Should -Be 'Ignore';
|
||||
}
|
||||
|
||||
It 'from Environment' {
|
||||
try {
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_ALIASREFERENCE = 'error';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_ALIASREFERENCE = 'Error';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
|
||||
# With int
|
||||
$Env:PSRULE_EXECUTION_ALIASREFERENCE = '3';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
}
|
||||
finally {
|
||||
Remove-Item 'Env:PSRULE_EXECUTION_ALIASREFERENCE' -Force;
|
||||
}
|
||||
}
|
||||
|
||||
It 'from parameter' {
|
||||
$option = New-PSRuleOption -ExecutionAliasReference 'Error' -Path $emptyOptionsFilePath;
|
||||
$option.Execution.AliasReference | Should -Be 'Error';
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.RuleInconclusive' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
|
@ -1015,53 +1107,6 @@ Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' {
|
|||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.DuplicateResourceId' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Error'
|
||||
}
|
||||
|
||||
It 'from Hashtable' {
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.DuplicateResourceId' = 'warn' };
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
|
||||
$option = New-PSRuleOption -Option @{ 'Execution.DuplicateResourceId' = 'Warn' };
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
|
||||
It 'from YAML' {
|
||||
$option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml');
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
|
||||
It 'from Environment' {
|
||||
try {
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_DUPLICATERESOURCEID = 'warn';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
|
||||
# With enum
|
||||
$Env:PSRULE_EXECUTION_DUPLICATERESOURCEID = 'Warn';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
|
||||
# With int
|
||||
$Env:PSRULE_EXECUTION_DUPLICATERESOURCEID = '2';
|
||||
$option = New-PSRuleOption;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
finally {
|
||||
Remove-Item 'Env:PSRULE_EXECUTION_DUPLICATERESOURCEID' -Force;
|
||||
}
|
||||
}
|
||||
|
||||
It 'from parameter' {
|
||||
$option = New-PSRuleOption -DuplicateResourceId 'Warn' -Path $emptyOptionsFilePath;
|
||||
$option.Execution.DuplicateResourceId | Should -Be 'Warn';
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.InitialSessionState' {
|
||||
It 'from default' {
|
||||
$option = New-PSRuleOption -Default;
|
||||
|
@ -2341,6 +2386,13 @@ Describe 'Set-PSRuleOption' -Tag 'Option','Set-PSRuleOption' {
|
|||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.Break' {
|
||||
It 'from parameter' {
|
||||
$option = Set-PSRuleOption -ExecutionBreak 'Never' @optionParams;
|
||||
$option.Execution.Break | Should -Be 'Never';
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Read Execution.SuppressionGroupExpired' {
|
||||
It 'from parameter' {
|
||||
$option = Set-PSRuleOption -SuppressionGroupExpired 'Error' @optionParams;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# These are options for unit tests
|
||||
|
||||
# Configure execution options.
|
||||
execution:
|
||||
break: Never
|
|
@ -106,7 +106,6 @@ public sealed class PipelineTests
|
|||
|
||||
var option = GetOption();
|
||||
option.Rule.Include = ["WithPathPrefix"];
|
||||
//option.Input.Format = InputFormat.File;
|
||||
var builder = PipelineBuilder.Invoke(GetSource(), option, null);
|
||||
var writer = new TestWriter(option);
|
||||
var pipeline = builder.Build(writer);
|
||||
|
|
Загрузка…
Ссылка в новой задаче