Skip to content

Commit c9e2207

Browse files
authored
chore: add code linting and formatting (#77)
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
1 parent 6f53ec8 commit c9e2207

7 files changed

Lines changed: 224 additions & 17 deletions

File tree

.editorconfig

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,4 @@ end_of_line = crlf
1818

1919
[*.{yml, yaml}]
2020
indent_size = 2
21-
22-
# Makefiles require tab indentation
23-
[{{M,m,GNU}akefile{,.*},*.mak,*.mk}]
24-
indent_style = tab
2521
end_of_line = lf

.github/workflows/ci.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
permissions: {}
8+
9+
jobs:
10+
test:
11+
name: Tests
12+
runs-on: windows-latest
13+
defaults:
14+
run:
15+
shell: pwsh
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
19+
- name: Install dependencies
20+
uses: potatoqualitee/psmodulecache@ee5e9494714abf56f6efbfa51527b2aec5c761b8 # v6.2.1
21+
with:
22+
modules-to-cache: PSScriptAnalyzer, Pester
23+
shell: pwsh
24+
- name: Run tests
25+
run: ./tests/run.ps1

.psformatrules.psd1

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
@{
2+
# OTBS
3+
IncludeRules = @(
4+
'PSPlaceOpenBrace',
5+
'PSPlaceCloseBrace',
6+
'PSUseConsistentWhitespace',
7+
'PSUseConsistentIndentation',
8+
'PSAlignAssignmentStatement',
9+
'PSAvoidSemicolonsAsLineTerminators',
10+
'PSAvoidUsingDoubleQuotesForConstantString',
11+
'PSUseCorrectCasing'
12+
)
13+
14+
Rules = @{
15+
PSPlaceOpenBrace = @{
16+
Enable = $true
17+
OnSameLine = $true
18+
NewLineAfter = $true
19+
IgnoreOneLineBlock = $true
20+
}
21+
22+
PSPlaceCloseBrace = @{
23+
Enable = $true
24+
NewLineAfter = $false
25+
IgnoreOneLineBlock = $true
26+
NoEmptyLineBefore = $false
27+
}
28+
29+
PSUseConsistentIndentation = @{
30+
Enable = $true
31+
Kind = 'space'
32+
PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
33+
IndentationSize = 4
34+
}
35+
36+
PSUseConsistentWhitespace = @{
37+
Enable = $true
38+
CheckInnerBrace = $true
39+
CheckOpenBrace = $true
40+
CheckOpenParen = $true
41+
CheckOperator = $true
42+
CheckPipe = $true
43+
CheckPipeForRedundantWhitespace = $false
44+
CheckSeparator = $true
45+
CheckParameter = $false
46+
IgnoreAssignmentOperatorInsideHashTable = $true
47+
}
48+
49+
PSAlignAssignmentStatement = @{
50+
Enable = $true
51+
CheckHashtable = $true
52+
}
53+
54+
PSAvoidSemicolonsAsLineTerminators = @{
55+
Enable = $true
56+
}
57+
58+
PSAvoidUsingDoubleQuotesForConstantString = @{
59+
Enable = $true
60+
}
61+
62+
PSUseCorrectCasing = @{
63+
Enable = $true
64+
}
65+
}
66+
}
67+

.pslintrules.psd1

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@{
2+
# Only diagnostic records of the specified severity will be generated.
3+
# Uncomment the following line if you only want Errors and Warnings but
4+
# not Information diagnostic records.
5+
Severity = @('Error', 'Warning')
6+
7+
# Analyze **only** the following rules. Use IncludeRules when you want
8+
# to invoke only a small subset of the default rules.
9+
# IncludeRules = @('PSAvoidDefaultValueSwitchParameter',
10+
# 'PSMisleadingBacktick',
11+
# 'PSMissingModuleManifestField',
12+
# 'PSReservedCmdletChar',
13+
# 'PSReservedParams',
14+
# 'PSShouldProcess',
15+
# 'PSUseApprovedVerbs',
16+
# 'PSAvoidUsingCmdletAliases',
17+
# 'PSUseDeclaredVarsMoreThanAssignments')
18+
19+
# Do not analyze the following rules. Use ExcludeRules when you have
20+
# commented out the IncludeRules settings above and want to include all
21+
# the default rules except for those you exclude below.
22+
# Note: if a rule is in both IncludeRules and ExcludeRules, the rule
23+
# will be excluded.
24+
ExcludeRules = @(
25+
# PSUseDeclaredVarsMoreThanAssignments doesn't currently work due to:
26+
# https://github.com/PowerShell/PSScriptAnalyzer/issues/636
27+
'PSUseDeclaredVarsMoreThanAssignments',
28+
# `Write-Log` uses `Write-Host` currently.
29+
'PSAvoidUsingWriteHost'
30+
)
31+
}

.vscode/settings.json

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
1-
// Configure PSScriptAnalyzer settings
21
{
3-
"powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1",
2+
"[powershell]": {
3+
"editor.formatOnSave": true,
4+
},
5+
"powershell.scriptAnalysis.settingsPath": ".pslintrules.psd1",
46
"powershell.codeFormatting.preset": "OTBS",
5-
"powershell.codeFormatting.alignPropertyValuePairs": true,
6-
"powershell.codeFormatting.ignoreOneLineBlock": true,
77
"powershell.codeFormatting.useConstantStrings": true,
88
"powershell.codeFormatting.useCorrectCasing": true,
9-
"powershell.codeFormatting.whitespaceBetweenParameters": true,
10-
"files.exclude": {
11-
"**/.git": true,
12-
"**/.svn": true,
13-
"**/.hg": true,
14-
"**/CVS": true,
15-
"**/.DS_Store": true,
16-
"**/tmp": true
17-
}
189
}

tests/Linter.Tests.ps1

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
Describe 'PowerShell Code Style' -Tag 'PSScriptAnalyzer' {
2+
BeforeAll {
3+
$formatSettings = "$PSScriptRoot\..\.psformatrules.psd1"
4+
$lintSettings = "$PSScriptRoot\..\.pslintrules.psd1"
5+
}
6+
7+
It 'PSScriptAnalyzer rules files should exist' {
8+
$formatSettings | Should -Exist
9+
$lintSettings | Should -Exist
10+
}
11+
12+
Context 'PowerShell code formatting' {
13+
BeforeAll {
14+
$records = Invoke-ScriptAnalyzer -Path "$PSScriptRoot\..\" `
15+
-Recurse -Settings $formatSettings
16+
}
17+
It 'Code should be formatted' {
18+
$records.Count | Should -Be 0
19+
}
20+
AfterAll {
21+
if ($records) {
22+
foreach ($r in $records) {
23+
$type = 'Unknown'
24+
switch -wildCard ($r.ScriptName) {
25+
'*.psm1' { $type = 'Module' }
26+
'*.ps1' { $type = 'Script' }
27+
'*.psd1' { $type = 'Manifest' }
28+
default { $type = 'Unknown' }
29+
}
30+
$scriptPath = Resolve-Path -Relative $r.ScriptPath
31+
$color = switch ($r.Severity) {
32+
'Error' { 'Red' }
33+
'Warning' { 'Yellow' }
34+
'Information' { 'White' }
35+
default { 'White' }
36+
}
37+
Write-Host -f $color " [!] $($r.Severity): $($r.Message)"
38+
Write-Host -f $color " $($r.RuleName) in $type`: $($scriptPath):$($r.Line)"
39+
}
40+
}
41+
}
42+
}
43+
44+
Context 'PowerShell code linting' {
45+
BeforeAll {
46+
$records = Invoke-ScriptAnalyzer -Path "$PSScriptRoot\..\" `
47+
-Recurse -Settings $lintSettings
48+
}
49+
It 'Code should be linted' {
50+
$records.Count | Should -Be 0
51+
}
52+
AfterAll {
53+
if ($records) {
54+
foreach ($r in $records) {
55+
$type = 'Unknown'
56+
switch -wildCard ($r.ScriptName) {
57+
'*.psm1' { $type = 'Module' }
58+
'*.ps1' { $type = 'Script' }
59+
'*.psd1' { $type = 'Manifest' }
60+
default { $type = 'Unknown' }
61+
}
62+
$scriptPath = Resolve-Path -Relative $r.ScriptPath
63+
$color = switch ($r.Severity) {
64+
'Error' { 'Red' }
65+
'Warning' { 'Yellow' }
66+
'Information' { 'White' }
67+
default { 'White' }
68+
}
69+
Write-Host -f $color " [!] $($r.Severity): $($r.Message)"
70+
Write-Host -f $color " $($r.RuleName) in $type`: $($scriptPath):$($r.Line)"
71+
}
72+
}
73+
}
74+
}
75+
}

tests/run.ps1

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#Requires -Version 5.1
2+
#Requires -Modules Pester
3+
#Requires -Modules PSScriptAnalyzer
4+
5+
$pesterConfig = New-PesterConfiguration -Hashtable @{
6+
Run = @{
7+
Path = "$PSScriptRoot"
8+
PassThru = $true
9+
}
10+
Should = @{
11+
# Continue running tests even if some assertions fail. This allows
12+
# Pester to collect and report all failures at the end of a test
13+
# instead of stopping at the first failing assertion.
14+
ErrorAction = 'Continue'
15+
}
16+
Output = @{
17+
StackTraceVerbosity = 'None'
18+
Verbosity = 'Detailed'
19+
}
20+
}
21+
$result = Invoke-Pester -Configuration $pesterConfig
22+
exit $result.FailedCount

0 commit comments

Comments
 (0)