Skip to content

Commit

Permalink
Fix PowerShell logging and add cross platform support #48 #49 (#51)
Browse files Browse the repository at this point in the history
- Fix propagation of informational messages to host from rule scripts and definitions #48
- Add support for cross-platform environments (Windows, Linux, and macOS) #49
  • Loading branch information
BernieWhite authored Jan 3, 2019
1 parent 1a641b3 commit a5912cc
Show file tree
Hide file tree
Showing 59 changed files with 854 additions and 332 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
- Add `Test-PSRule` command to return an overall `$True` or `$False` after evaluating rules for an object [#30](https://github.com/BernieWhite/PSRule/issues/30)
- Improve reporting of inconclusive results and objects that are not processed by any rule [#46](https://github.com/BernieWhite/PSRule/issues/46)
- Inconclusive results and objects not processed will return a warning
- Fix propagation of informational messages to host from rule scripts and definitions [#48](https://github.com/BernieWhite/PSRule/issues/48)
- Add support for cross-platform environments (Windows, Linux, and macOS) [#49](https://github.com/BernieWhite/PSRule/issues/49)

## v0.1.0

Expand Down
19 changes: 16 additions & 3 deletions PSRule.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ param (
[Parameter(Mandatory = $False)]
[Switch]$CodeCoverage = $False,

[Parameter(Mandatory = $False)]
[Switch]$Benchmark = $False,

[Parameter(Mandatory = $False)]
[String]$ArtifactPath = (Join-Path -Path $PWD -ChildPath out/modules)
)

Expand Down Expand Up @@ -99,6 +103,13 @@ task BuildDotNet {
}
}

task TestDotNet {
exec {
# Test library
dotnet test --logger trx -r (Join-Path $PWD -ChildPath reports/) tests/PSRule.Tests
}
}

task CopyModule {
CopyModuleFiles -Path src/PSRule -DestinationPath out/modules/PSRule;

Expand Down Expand Up @@ -213,7 +224,7 @@ task PSScriptAnalyzer {
Import-Module -Name PSScriptAnalyzer -Verbose:$False;
}

task TestModule Pester, PSScriptAnalyzer, {
task TestModule TestDotNet, Pester, PSScriptAnalyzer, {

# Run Pester tests
$pesterParams = @{ Path = $PWD; OutputFile = 'reports/Pester.xml'; OutputFormat = 'NUnitXml'; PesterOption = @{ IncludeVSCodeMarker = $True }; PassThru = $True; };
Expand Down Expand Up @@ -242,7 +253,9 @@ task TestModule Pester, PSScriptAnalyzer, {
}

task Benchmark {
dotnet run -p src/PSRule.Benchmark -f net472 -c Release -- benchmark --output $PWD;
if ($Benchmark -or $BuildTask -eq 'Benchmark') {
dotnet run -p src/PSRule.Benchmark -f netcoreapp2.1 -c Release -- benchmark --output $PWD;
}
}

# Synopsis: Run script analyzer
Expand Down Expand Up @@ -270,7 +283,7 @@ task BuildSite {
}

# Synopsis: Build and clean.
task . Build, Test
task . Build, Test, Benchmark

# Synopsis: Build the project
task Build Clean, BuildModule, BuildHelp, VersionModule
Expand Down
15 changes: 5 additions & 10 deletions PSRule.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSRule", "src\PSRule\PSRule
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSRule.Benchmark", "src\PSRule.Benchmark\PSRule.Benchmark.csproj", "{0693DC93-1F72-410A-B77F-A81A92391995}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8FFA09C2-4E4A-4F9D-89E4-744E3ACD5280}"
ProjectSection(SolutionItems) = preProject
dotnet.psess = dotnet.psess
EndProjectSection
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSRule.Tests", "tests\PSRule.Tests\PSRule.Tests.csproj", "{05D23A4D-BD15-4E41-9482-0CC083F5F447}"
EndProject
Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Expand All @@ -29,14 +23,15 @@ Global
{0693DC93-1F72-410A-B77F-A81A92391995}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0693DC93-1F72-410A-B77F-A81A92391995}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0693DC93-1F72-410A-B77F-A81A92391995}.Release|Any CPU.Build.0 = Release|Any CPU
{05D23A4D-BD15-4E41-9482-0CC083F5F447}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{05D23A4D-BD15-4E41-9482-0CC083F5F447}.Debug|Any CPU.Build.0 = Debug|Any CPU
{05D23A4D-BD15-4E41-9482-0CC083F5F447}.Release|Any CPU.ActiveCfg = Release|Any CPU
{05D23A4D-BD15-4E41-9482-0CC083F5F447}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {533491EB-BAE9-472E-B57F-A675ECD335B5}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# PSRule

A PowerShell module with commands to validate objects on the pipeline using PowerShell syntax.
A cross-platform PowerShell module (Windows, Linux, and macOS) with commands to validate objects on the pipeline using PowerShell syntax.

![ci-badge]

Expand Down
39 changes: 35 additions & 4 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# Azure DevOps
# Build pipeline for PSRule

strategy:
matrix:
Linux:
imageName: 'ubuntu-16.04'
MacOS:
imageName: 'macos-10.13'
Windows:
imageName: 'vs2017-win2016'
publishModule: 'true'

variables:
buildConfiguration: 'Release'
version: '0.2.0'
Expand All @@ -12,23 +22,43 @@ trigger:
- master

pool:
vmImage: VS2017-Win2016
vmImage: $(imageName)

steps:

# Install pipeline dependencies and build module
- powershell: ./scripts/pipeline-build.ps1 -File ./PSRule.build.ps1 -Configuration $(buildConfiguration) -ModuleVersion $(Build.BuildNumber) -ReleaseVersion "$(Release.Version)"
displayName: 'Build module'

# Publish test results
# Run module benchmark
- powershell: ./scripts/pipeline-build.ps1 -Task Benchmark -File ./PSRule.build.ps1 -Configuration $(buildConfiguration) -ModuleVersion $(Build.BuildNumber) -ReleaseVersion "$(Release.Version)"
displayName: 'Benchmark'
condition: eq(variables['benchmark'], 'true')

# DotNet test results
- task: PublishTestResults@2
displayName: 'Publish unit test results'
inputs:
testRunTitle: 'DotNet on $(imageName)'
testRunner: VSTest
testResultsFiles: 'reports/*.trx'
mergeTestResults: true
platform: $(imageName)
configuration: $(buildConfiguration)
publishRunAttachments: true
condition: succeededOrFailed()

# Pester test results
- task: PublishTestResults@2
displayName: 'Publish test results'
displayName: 'Publish Pester results'
inputs:
testRunTitle: 'Pester unit tests'
testRunTitle: 'Pester on $(imageName)'
testRunner: NUnit
testResultsFiles: 'reports/*.xml'
mergeTestResults: true
platform: $(imageName)
configuration: $(buildConfiguration)
publishRunAttachments: true
condition: succeededOrFailed()

# Generate artifacts
Expand All @@ -37,3 +67,4 @@ steps:
inputs:
PathtoPublish: out/modules/PSRule
ArtifactName: PSRule
condition: and(succeeded(), eq(variables['publishModule'], 'true'))
16 changes: 16 additions & 0 deletions docs/scenarios/benchmark/PSRule.Benchmark.PSRule-report-github.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
``` ini

BenchmarkDotNet=v0.11.3, OS=Windows 10.0.17763.195 (1809/October2018Update/Redstone5)
Intel Core i7-6600U CPU 2.60GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
.NET Core SDK=2.2.100
[Host] : .NET Core 2.1.6 (CoreCLR 4.6.27019.06, CoreFX 4.6.27019.05), 64bit RyuJIT
DefaultJob : .NET Core 2.1.6 (CoreCLR 4.6.27019.06, CoreFX 4.6.27019.05), 64bit RyuJIT


```
| Method | Mean | Error | StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|-------------- |-----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
| Invoke | 117.257 ms | 2.1959 ms | 2.1567 ms | 8400.0000 | 400.0000 | - | 17355.83 KB |
| InvokeIf | 128.418 ms | 3.0122 ms | 3.8095 ms | 9750.0000 | 500.0000 | - | 20301.73 KB |
| InvokeSummary | 116.479 ms | 1.9241 ms | 1.7998 ms | 8400.0000 | - | - | 17301.03 KB |
| Get | 8.921 ms | 0.0864 ms | 0.0766 ms | 93.7500 | - | - | 203.82 KB |
4 changes: 3 additions & 1 deletion docs/scenarios/install-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
## Prerequisites

- Windows PowerShell 5.1 with .NET Framework 4.7.2+ or
- PowerShell Core 6.0
- PowerShell Core 6.0 or greater on Windows, macOS and Linux

For a list of platforms that PowerShell Core is supported on [see](https://github.com/PowerShell/PowerShell#get-powershell).

## Getting the modules

Expand Down
3 changes: 3 additions & 0 deletions scripts/pipeline-build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ param (
[Parameter(Mandatory = $False)]
[Switch]$CodeCoverage = $False,

[Parameter(Mandatory = $False)]
[Switch]$Benchmark = $False,

[Parameter(Mandatory = $False)]
[String]$ArtifactPath = (Join-Path -Path $PWD -ChildPath out/modules)
)
Expand Down
16 changes: 5 additions & 11 deletions src/PSRule.Benchmark/PSRule.Benchmark.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>

<!-- <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp2.1|AnyCPU'">
<Optimize>false</Optimize>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp2.1|AnyCPU'">
<DefineConstants />
</PropertyGroup> -->

<PropertyGroup Condition="'$(Configuration)'=='Release'">
<DefineConstants>TRACE;BENCHMARK</DefineConstants>
</PropertyGroup>
Expand All @@ -24,9 +15,12 @@
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.11.3" />
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<PackageReference Include="Microsoft.PowerShell.5.1.ReferenceAssemblies" Version="1.0.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
Expand Down
42 changes: 21 additions & 21 deletions src/PSRule.Benchmark/PSRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,35 @@ public void Prepare()

private void PrepareGetPipeline()
{
var getBuilder = PipelineBuilder.Get();
getBuilder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
getBuilder.FilterBy(new string[] { "Benchmark" }, null);
_GetPipeline = getBuilder.Build();
var builder = PipelineBuilder.Get();
builder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
builder.FilterBy(new string[] { "Benchmark" }, null);
_GetPipeline = builder.Build();
}

private void PrepareInvokePipeline()
{
var invokeBuilder = PipelineBuilder.Invoke();
invokeBuilder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
invokeBuilder.FilterBy(new string[] { "Benchmark" }, null);
_InvokePipeline = invokeBuilder.Build();
var builder = PipelineBuilder.Invoke();
builder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
builder.FilterBy(new string[] { "Benchmark" }, null);
_InvokePipeline = builder.Build();
}

private void PrepareInvokeIfPipeline()
{
var invokeBuilder = PipelineBuilder.Invoke();
invokeBuilder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
invokeBuilder.FilterBy(new string[] { "BenchmarkIf" }, null);
_InvokeIfPipeline = invokeBuilder.Build();
var builder = PipelineBuilder.Invoke();
builder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
builder.FilterBy(new string[] { "BenchmarkIf" }, null);
_InvokeIfPipeline = builder.Build();
}

private void PrepareInvokeSummaryPipeline()
{
var invokeBuilder = PipelineBuilder.Invoke();
invokeBuilder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
invokeBuilder.FilterBy(new string[] { "Benchmark" }, null);
invokeBuilder.As(Configuration.ResultFormat.Summary);
_InvokeSummaryPipeline = invokeBuilder.Build();
var builder = PipelineBuilder.Invoke();
builder.Source(new string[] { Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Benchmark.Rule.ps1") });
builder.FilterBy(new string[] { "Benchmark" }, null);
builder.As(Configuration.ResultFormat.Summary);
_InvokeSummaryPipeline = builder.Build();
}

private void PrepareTargetObjects()
Expand All @@ -98,11 +98,11 @@ private void PrepareTargetObjects()
[Benchmark]
public void Invoke() => _InvokePipeline.Process(_TargetObject).Consume(new Consumer());

//[Benchmark]
//public void InvokeIf() => _InvokeIfPipeline.Process(_TargetObject).Consume(new Consumer());
[Benchmark]
public void InvokeIf() => _InvokeIfPipeline.Process(_TargetObject).Consume(new Consumer());

//[Benchmark]
//public void InvokeSummary() => _InvokeSummaryPipeline.Process(_TargetObject);
[Benchmark]
public void InvokeSummary() => _InvokeSummaryPipeline.Process(_TargetObject);

[Benchmark]
public void Get() => _GetPipeline.Process().Consume(new Consumer());
Expand Down
2 changes: 1 addition & 1 deletion src/PSRule.Benchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private static void DebugProfile()
var profile = new PSRule();
profile.Prepare();

for (var i = 0; i < 1000; i++)
for (var i = 0; i < 10; i++)
{
profile.Invoke();
}
Expand Down
15 changes: 4 additions & 11 deletions src/PSRule/Commands/AssertAllOfCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,13 @@ internal sealed class AssertAllOfCommand : RuleKeyword

protected override void ProcessRecord()
{
try
{
var invokeResult = new RuleConditionResult(Body.Invoke());
var invokeResult = RuleConditionResult.Create(Body.Invoke());

var result = invokeResult.AllOf;
var result = invokeResult.AllOf();

PipelineContext.CurrentThread.WriteVerboseConditionResult(condition: "[AllOf]", pass: invokeResult.Pass, count: invokeResult.Count, outcome: result);
PipelineContext.CurrentThread.VerboseConditionResult(condition: RuleLanguageNouns.AllOf, pass: invokeResult.Pass, count: invokeResult.Count, outcome: result);

WriteObject(result);
}
finally
{

}
WriteObject(result);
}
}
}
15 changes: 4 additions & 11 deletions src/PSRule/Commands/AssertAnyOfCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,13 @@ internal sealed class AssertAnyOfCommand : RuleKeyword

protected override void ProcessRecord()
{
try
{
var invokeResult = new RuleConditionResult(Body.Invoke());
var invokeResult = RuleConditionResult.Create(Body.Invoke());

var result = invokeResult.AnyOf;
var result = invokeResult.AnyOf();

PipelineContext.CurrentThread.WriteVerboseConditionResult(condition: "[AnyOf]", pass: invokeResult.Pass, count: invokeResult.Count, outcome: result);
PipelineContext.CurrentThread.VerboseConditionResult(condition: RuleLanguageNouns.AnyOf, pass: invokeResult.Pass, count: invokeResult.Count, outcome: result);

WriteObject(result);
}
finally
{

}
WriteObject(result);
}
}
}
Loading

0 comments on commit a5912cc

Please sign in to comment.