Skip to content

Commit

Permalink
(#32) Add PSScriptAnalyzer
Browse files Browse the repository at this point in the history
This adds a task to run PSScriptAnalyzer. It utilizes the Cake.Powershell
module to run a script that will get ps1/psm1 files that are not excluded
and run them through the specified settings file.

Either a default formatting only run can be done, or custom run(s) can be
specified. A custom base analysis path, setting file and set of folder
exclusions can be specified for each run. For example, a custom run can
be created to check that the Chocolatey powershell helpers use only the
PSv2 cmdlets.

The default run is for formatting, it checks files against the build in
formatting related rules. This run can be expanded in the future, once
enough projects are up to a baseline of good scripting practices.
  • Loading branch information
TheCakeIsNaOH committed Aug 16, 2022
1 parent 4df729e commit fb2fa47
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Chocolatey.Cake.Recipe/Content/analyzing.cake
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,5 @@ BuildParameters.Tasks.CreateIssuesReportTask = Task("CreateIssuesReport")

BuildParameters.Tasks.AnalyzeTask = Task("Analyze")
.IsDependentOn("InspectCode")
.IsDependentOn("CreateIssuesReport");
.IsDependentOn("CreateIssuesReport")
.IsDependentOn("Run-PSScriptAnalyzer");
70 changes: 70 additions & 0 deletions Chocolatey.Cake.Recipe/Content/formatting-settings.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
@{
IncludeRules = @(
'PSUseBOMForUnicodeEncodedFile',
'PSMisleadingBacktick',
'PSAvoidUsingCmdletAliases',
'PSAvoidTrailingWhitespace',
'PSAvoidSemicolonsAsLineTerminators',
'PSUseCorrectCasing',
'PSPlaceOpenBrace',
'PSPlaceCloseBrace',
'PSAlignAssignmentStatement',
'PSUseConsistentWhitespace',
'PSUseConsistentIndentation'
)

Rules = @{

<#
PSAvoidUsingCmdletAliases = @{
'allowlist' = @('')
}#>

PSAvoidSemicolonsAsLineTerminators = @{
Enable = $true
}

PSUseCorrectCasing = @{
Enable = $true
}

PSPlaceOpenBrace = @{
Enable = $true
OnSameLine = $true
NewLineAfter = $true
IgnoreOneLineBlock = $false
}

PSPlaceCloseBrace = @{
Enable = $true
NewLineAfter = $true
IgnoreOneLineBlock = $false
NoEmptyLineBefore = $true
}

PSAlignAssignmentStatement = @{
Enable = $true
CheckHashtable = $true
}

PSUseConsistentIndentation = @{
Enable = $true
Kind = 'space'
PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
IndentationSize = 4
}

PSUseConsistentWhitespace = @{
Enable = $true
CheckInnerBrace = $true
CheckOpenBrace = $true
CheckOpenParen = $true
CheckOperator = $true
CheckPipe = $true
CheckPipeForRedundantWhitespace = $false
CheckSeparator = $true
CheckParameter = $false
IgnoreAssignmentOperatorInsideHashTable = $true
}
}
}
7 changes: 7 additions & 0 deletions Chocolatey.Cake.Recipe/Content/parameters.cake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static class BuildParameters
public static Func<FilePathCollection> GetFilesToObfuscate { get; private set; }
public static Func<FilePathCollection> GetFilesToSign { get; private set; }
public static Func<List<ILMergeConfig>> GetILMergeConfigs { get; private set; }
public static Func<List<PSScriptAnalyzerSettings>> GetPSScriptAnalyzerSettings { get; private set; }
public static Func<FilePathCollection> GetMsisToSign { get; private set; }
public static Func<FilePathCollection> GetProjectsToPack { get; private set; }
public static Func<FilePathCollection> GetScriptsToSign { get; private set; }
Expand Down Expand Up @@ -89,6 +90,7 @@ public static class BuildParameters
public static bool ShouldRunReportUnit { get; private set; }
public static bool ShouldRunTransifex { get; set; }
public static bool ShouldRunxUnit { get; private set; }
public static bool ShouldRunPSScriptAnalyzer { get; private set; }
public static bool ShouldStrongNameOutputAssemblies { get; private set; }
public static bool ShouldStrongNameSignDependentAssemblies { get; private set; }
public static DirectoryPath SolutionDirectoryPath { get; private set; }
Expand Down Expand Up @@ -197,6 +199,7 @@ public static class BuildParameters
context.Information("ShouldRunReportUnit: {0}", BuildParameters.ShouldRunReportUnit);
context.Information("ShouldRunTransifex: {0}", BuildParameters.ShouldRunTransifex);
context.Information("ShouldRunxUnit: {0}", BuildParameters.ShouldRunxUnit);
context.Information("ShouldRunPSScriptAnalyzer: {0}", BuildParameters.ShouldRunPSScriptAnalyzer);
context.Information("ShouldStrongNameOutputAssemblies: {0}", BuildParameters.ShouldStrongNameOutputAssemblies);
context.Information("ShouldStrongNameSignDependentAssemblies: {0}", BuildParameters.ShouldStrongNameSignDependentAssemblies);
context.Information("SolutionFilePath: {0}", context.MakeAbsolute((FilePath)SolutionFilePath));
Expand Down Expand Up @@ -231,6 +234,7 @@ public static class BuildParameters
Func<FilePathCollection> getFilesToObfuscate = null,
Func<FilePathCollection> getFilesToSign = null,
Func<List<ILMergeConfig>> getILMergeConfigs = null,
Func<List<PSScriptAnalyzerSettings>> getPSScriptAnalyzerSettings = null,
Func<FilePathCollection> getMsisToSign = null,
Func<FilePathCollection> getProjectsToPack = null,
Func<FilePathCollection> getScriptsToSign = null,
Expand Down Expand Up @@ -282,6 +286,7 @@ public static class BuildParameters
bool shouldRunReportUnit = true,
bool? shouldRunTransifex = null,
bool shouldRunxUnit = true,
bool shouldRunPSScriptAnalyzer = true,
bool shouldStrongNameOutputAssemblies = true,
bool shouldStrongNameSignDependentAssemblies = true,
DirectoryPath solutionDirectoryPath = null,
Expand Down Expand Up @@ -337,6 +342,7 @@ public static class BuildParameters
GetFilesToObfuscate = getFilesToObfuscate;
GetFilesToSign = getFilesToSign;
GetILMergeConfigs = getILMergeConfigs;
GetPSScriptAnalyzerSettings = getPSScriptAnalyzerSettings;
GetMsisToSign = getMsisToSign;
GetProjectsToPack = getProjectsToPack;
GetScriptsToSign = getScriptsToSign;
Expand Down Expand Up @@ -399,6 +405,7 @@ public static class BuildParameters
ShouldRunReportUnit = shouldRunReportUnit;
ShouldRunTransifex = shouldRunTransifex ?? TransifexIsConfiguredForRepository(context);
ShouldRunxUnit = shouldRunxUnit;
ShouldRunPSScriptAnalyzer = shouldRunPSScriptAnalyzer;
ShouldStrongNameOutputAssemblies = shouldStrongNameOutputAssemblies;
ShouldStrongNameSignDependentAssemblies = shouldStrongNameSignDependentAssemblies;
SolutionDirectoryPath = solutionDirectoryPath ?? sourceDirectoryPath.Combine(title);
Expand Down
76 changes: 76 additions & 0 deletions Chocolatey.Cake.Recipe/Content/psscriptanalyzer.cake
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
BuildParameters.Tasks.PSScriptAnalyzerTask = Task("Run-PSScriptAnalyzer")
.WithCriteria(() => BuildParameters.ShouldRunPSScriptAnalyzer, "Skipping because PSScriptAnalyzer is not enabled")
.Does(() =>
{
var powerShellAnalysisScript = GetFiles("./tools/Chocolatey.Cake.Recipe*/Content/run-psscriptanalyzer.ps1").FirstOrDefault();

if (powerShellAnalysisScript == null)
{
Warning("Unable to find PowerShell Analysis script, so unable to run analysis.");
return;
}

if (BuildParameters.GetPSScriptAnalyzerSettings != null)
{
foreach (var PSScriptAnalyzerSetting in BuildParameters.GetPSScriptAnalyzerSettings())
{
Information(string.Format("Running PSScriptAnalyzer {0}", PSScriptAnalyzerSetting.Name);

StartPowershellFile(MakeAbsolute(powerShellAnalysisScript), new PowershellSettings()
.WithModule("PSScriptAnalyzer")
.SetFormatOutput(true)
.WithArguments(args => {
args.AppendQuoted("AnalyzePath", PSScriptAnalyzerSetting.AnalysisPath.ToString())
.AppendQuoted("SettingsPath", PSScriptAnalyzerSetting.SettingsPath.ToString())
.AppendArray("ExcludePaths", PSScriptAnalyzerSetting.ExcludePaths);
}));
}
}
else
{
Information("There are no PSScriptAnalyzer Settings defined for this build, running with default format checking settings.");

var settingsFile = GetFiles("./tools/Chocolatey.Cake.Recipe*/Content/formatting-settings.psd1").FirstOrDefault();

if (settingsFile == null)
{
Warning("Unable to find PowerShell Analysis settings, so unable to run analysis.");
return;
}

var excludePaths = new List<String> { "tools", "code_drop"};

StartPowershellFile(MakeAbsolute(powerShellAnalysisScript), new PowershellSettings()
.WithModule("PSScriptAnalyzer")
.SetFormatOutput(true)
.WithArguments(args => {
args.AppendQuoted("AnalyzePath", BuildParameters.RootDirectoryPath.ToString())
.AppendQuoted("SettingsPath", settingsFile.ToString())
.AppendArray("ExcludePaths", excludePaths);
}));
}
});

public class PSScriptAnalyzerSettings
{
public FilePath AnalysisPath { get; set; }
public FilePath SettingsPath { get; set; }
public List<String> ExcludePaths { get; set; }
public string Name { get; set; }

public PSScriptAnalyzerSettings()
{
Name = "Unnamed";
}

public PSScriptAnalyzerSettings(FilePath analysisPath,
FilePath settingsPath,
List<String> excludePaths = null,
string name = "Unnamed")
{
AnalysisPath = analysisPath;
SettingsPath = settingsPath;
ExcludePaths = excludePaths;
Name = name;
}
}
51 changes: 51 additions & 0 deletions Chocolatey.Cake.Recipe/Content/run-psscriptanalyzer.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[cmdletBinding()]
Param(
[Parameter()]
[String]
$AnalyzePath,

[Parameter()]
[String]
$SettingsPath,

[Parameter()]
[String[]]
$ExcludePaths
)

#Requires -Modules PSScriptAnalyzer

Push-Location -Path $AnalyzePath

try {
if ($PSBoundParameters.ContainsKey('ExcludePaths')) {
$ExcludePaths = $ExcludePaths | ForEach-Object { (Resolve-Path -Path $_).Path }
}

$scripts = Get-ChildItem -Path $AnalyzePath -Filter "*.ps1" -Recurse | ForEach-Object {
if ($PSBoundParameters.ContainsKey('ExcludePaths')) {
foreach ($path in $ExcludePaths) {
if ($_.FullName.StartsWith($path)) {
return
}
}
}
$_
}
$modules = Get-ChildItem -Path $AnalyzePath -Filter "*.psm1" -Recurse | ForEach-Object {
if ($PSBoundParameters.ContainsKey('ExcludePaths')) {
foreach ($path in $ExcludePaths) {
if ($_.FullName.StartsWith($path)) {
return
}
}
}
$_
}

$modules | Invoke-ScriptAnalyzer -Settings $SettingsPath | Select-Object RuleName, ScriptPath, Line, Message
$Scripts | Invoke-ScriptAnalyzer -Settings $SettingsPath | Select-Object RuleName, ScriptPath, Line, Message
}
finally {
Pop-Location
}
1 change: 1 addition & 0 deletions Chocolatey.Cake.Recipe/Content/tasks.cake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class BuildTasks
public CakeTaskBuilder InspectCodeTask { get; set; }
public CakeTaskBuilder CreateIssuesReportTask { get; set; }
public CakeTaskBuilder AnalyzeTask { get; set; }
public CakeTaskBuilder PSScriptAnalyzerTask { get; set; }

// Eazfuscator Tasks
public CakeTaskBuilder ObfuscateAssembliesTask { get; set; }
Expand Down

0 comments on commit fb2fa47

Please sign in to comment.