Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PowerShell formatter linter #2176

Merged
merged 10 commits into from
Dec 26, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions .automation/generated/linter-helps.json
Original file line number Diff line number Diff line change
Expand Up @@ -4084,6 +4084,123 @@
" prepend the command parameters with a hyphen (-), not a forward slash (/).",
""
],
"powershell_formatter": [
"",
"PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]",
" [-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]",
" [-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]",
" [-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]",
" [-ConfigurationName <string>]",
" [-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]",
" [-Command { - | <script-block> [-args <arg-array>]",
" | <string> [<CommandParameters>] } ]",
"",
"PowerShell[.exe] -Help | -? | /?",
"",
"-PSConsoleFile",
" Loads the specified Windows PowerShell console file. To create a console",
" file, use Export-Console in Windows PowerShell.",
"",
"-Version",
" Starts the specified version of Windows PowerShell.",
" Enter a version number with the parameter, such as \"-version 2.0\".",
"",
"-NoLogo",
" Hides the copyright banner at startup.",
"",
"-NoExit",
" Does not exit after running startup commands.",
"",
"-Sta",
" Starts the shell using a single-threaded apartment.",
" Single-threaded apartment (STA) is the default.",
"",
"-Mta",
" Start the shell using a multithreaded apartment.",
"",
"-NoProfile",
" Does not load the Windows PowerShell profile.",
"",
"-NonInteractive",
" Does not present an interactive prompt to the user.",
"",
"-InputFormat",
" Describes the format of data sent to Windows PowerShell. Valid values are",
" \"Text\" (text strings) or \"XML\" (serialized CLIXML format).",
"",
"-OutputFormat",
" Determines how output from Windows PowerShell is formatted. Valid values",
" are \"Text\" (text strings) or \"XML\" (serialized CLIXML format).",
"",
"-WindowStyle",
" Sets the window style to Normal, Minimized, Maximized or Hidden.",
"",
"-EncodedCommand",
" Accepts a base-64-encoded string version of a command. Use this parameter",
" to submit commands to Windows PowerShell that require complex quotation",
" marks or curly braces.",
"",
"-ConfigurationName",
" Specifies a configuration endpoint in which Windows PowerShell is run.",
" This can be any endpoint registered on the local machine including the",
" default Windows PowerShell remoting endpoints or a custom endpoint having",
" specific user role capabilities.",
"",
"-File",
" Runs the specified script in the local scope (\"dot-sourced\"), so that the",
" functions and variables that the script creates are available in the",
" current session. Enter the script file path and any parameters.",
" File must be the last parameter in the command, because all characters",
" typed after the File parameter name are interpreted",
" as the script file path followed by the script parameters.",
"",
"-ExecutionPolicy",
" Sets the default execution policy for the current session and saves it",
" in the $env:PSExecutionPolicyPreference environment variable.",
" This parameter does not change the Windows PowerShell execution policy",
" that is set in the registry.",
"",
"-Command",
" Executes the specified commands (and any parameters) as though they were",
" typed at the Windows PowerShell command prompt, and then exits, unless",
" NoExit is specified. The value of Command can be \"-\", a string. or a",
" script block.",
"",
" If the value of Command is \"-\", the command text is read from standard",
" input.",
"",
" If the value of Command is a script block, the script block must be enclosed",
" in braces ({}). You can specify a script block only when running PowerShell.exe",
" in Windows PowerShell. The results of the script block are returned to the",
" parent shell as deserialized XML objects, not live objects.",
"",
" If the value of Command is a string, Command must be the last parameter",
" in the command , because any characters typed after the command are",
" interpreted as the command arguments.",
"",
" To write a string that runs a Windows PowerShell command, use the format:",
" \"& {<command>}\"",
" where the quotation marks indicate a string and the invoke operator (&)",
" causes the command to be executed.",
"",
"-Help, -?, /?",
" Shows this message. If you are typing a PowerShell.exe command in Windows",
" PowerShell, prepend the command parameters with a hyphen (-), not a forward",
" slash (/). You can use either a hyphen or forward slash in Cmd.exe.",
"",
"EXAMPLES",
" PowerShell -PSConsoleFile SqlSnapIn.Psc1",
" PowerShell -version 2.0 -NoLogo -InputFormat text -OutputFormat XML",
" PowerShell -ConfigurationName AdminRoles",
" PowerShell -Command {Get-EventLog -LogName security}",
" PowerShell -Command \"& {Get-EventLog -LogName security}\"",
"",
" # To use the -EncodedCommand parameter:",
" $command = 'dir \"c:\\program files\" '",
" $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)",
" $encodedCommand = [Convert]::ToBase64String($bytes)",
" powershell.exe -encodedCommand $encodedCommand"
],
"prettier": [
"Usage: prettier [options] [file/dir/glob ...]",
"",
Expand Down
5 changes: 5 additions & 0 deletions .automation/generated/linter-links-previews.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
"image": "https://repository-images.githubusercontent.com/33149177/18c68000-a5b0-11e9-9d88-c03ff0e21635",
"title": "PowerShell/PSScriptAnalyzer"
},
"powershell_formatter": {
"description": "Download ScriptAnalyzer from PowerShellGallery. Contribute to PowerShell/PSScriptAnalyzer development by creating an account on GitHub.",
"image": "https://repository-images.githubusercontent.com/33149177/18c68000-a5b0-11e9-9d88-c03ff0e21635",
"title": "GitHub - PowerShell/PSScriptAnalyzer: Download ScriptAnalyzer from PowerShellGallery"
},
"prettier": {
"description": "Opinionated Code Formatter",
"image": "https://prettier.io/icon.png",
Expand Down
1 change: 1 addition & 0 deletions .automation/generated/linter-versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"phpstan": "1.9.4",
"pmd": "6.48.0",
"powershell": "7.3.1",
"powershell_formatter": "5.1.22621",
"prettier": "2.8.1",
"proselint": "0.13.0",
"protolint": "0.42.2",
Expand Down
14 changes: 14 additions & 0 deletions .automation/test/powershell_formatter/powershell_bad_1.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#Plaintext Parameters
function BadFunction {
param(
[String]$Username = 'me',
[String]$Password = 'password'
)
$Username
$Password
$VariableThatIsNotUsedLater = '5'
try {
'Empty Catch Block'
} catch {}
}

3 changes: 3 additions & 0 deletions .automation/test/powershell_formatter/powershell_bad_1.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
'Hello'='World
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Write-Output "hello world!
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Write-Output "hello world!"
3 changes: 3 additions & 0 deletions .automation/test/powershell_formatter/powershell_good_1.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
'Hello'='World'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Write-Output "hello world!"
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,10 @@ RUN curl --retry 5 --retry-delay 5 -sLO "${ARM_TTK_URI}" \
# powershell installation
&& pwsh -c 'Install-Module -Name PSScriptAnalyzer -RequiredVersion ${PSSA_VERSION} -Scope AllUsers -Force' \

# powershell_formatter installation
# Next line commented because already managed by another linter
# RUN pwsh -c 'Install-Module -Name PSScriptAnalyzer -RequiredVersion ${PSSA_VERSION} -Scope AllUsers -Force'

# protolint installation
# Managed with COPY --from=protolint /usr/local/bin/protolint /usr/bin/

Expand Down
4 changes: 4 additions & 0 deletions flavors/dotnet/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ RUN curl --retry 5 --retry-delay 5 -sLO "${ARM_TTK_URI}" \
# powershell installation
&& pwsh -c 'Install-Module -Name PSScriptAnalyzer -RequiredVersion ${PSSA_VERSION} -Scope AllUsers -Force' \

# powershell_formatter installation
# Next line commented because already managed by another linter
# RUN pwsh -c 'Install-Module -Name PSScriptAnalyzer -RequiredVersion ${PSSA_VERSION} -Scope AllUsers -Force'

# protolint installation
# Managed with COPY --from=protolint /usr/local/bin/protolint /usr/bin/

Expand Down
1 change: 1 addition & 0 deletions flavors/dotnet/flavor.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"MARKDOWN_MARKDOWN_TABLE_FORMATTER",
"OPENAPI_SPECTRAL",
"POWERSHELL_POWERSHELL",
"POWERSHELL_POWERSHELL_FORMATTER",
"PROTOBUF_PROTOLINT",
"REPOSITORY_CHECKOV",
"REPOSITORY_GIT_DIFF",
Expand Down
1 change: 1 addition & 0 deletions megalinter/descriptors/all_flavors.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@
"MARKDOWN_MARKDOWN_TABLE_FORMATTER",
"OPENAPI_SPECTRAL",
"POWERSHELL_POWERSHELL",
"POWERSHELL_POWERSHELL_FORMATTER",
"PROTOBUF_PROTOLINT",
"REPOSITORY_CHECKOV",
"REPOSITORY_GIT_DIFF",
Expand Down
28 changes: 25 additions & 3 deletions megalinter/descriptors/powershell.megalinter-descriptor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ file_extensions:
- ".pssc"
- ".psrc"
- ".cdxml"
# Reference: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-7
# Reference: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux
# Slightly modified to always retrieve latest stable Powershell version
# If changing PWSH_VERSION='latest' to a specific version, use format PWSH_VERSION='tags/v7.0.2'
install:
Expand All @@ -36,8 +36,8 @@ linters:
linter_url: https://github.com/PowerShell/PSScriptAnalyzer
linter_repo: https://github.com/PowerShell/PSScriptAnalyzer
linter_image_url: https://github.com/PowerShell/PSScriptAnalyzer/raw/master/logo.png
linter_rules_configuration_url: https://github.com/PowerShell/PSScriptAnalyzer#explicit
linter_rules_inline_disable_url: https://github.com/PowerShell/PSScriptAnalyzer#suppressing-rules
linter_rules_configuration_url: https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/using-scriptanalyzer?view=ps-modules#explicit
linter_rules_inline_disable_url: https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/using-scriptanalyzer?view=ps-modules#suppressing-rules
config_file_name: .powershell-psscriptanalyzer.psd1
cli_lint_fix_arg_name: "-Fix"
version_extract_regex: "(\\d+) *(\\d+) *(\\d+)"
Expand All @@ -53,3 +53,25 @@ linters:
vscode:
- name: VSCode PowerShell extension
url: https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell
# Internal powershell linter
- class: PowershellLinter
linter_name: powershell_formatter
linter_url: https://github.com/PowerShell/PSScriptAnalyzer
bdovaz marked this conversation as resolved.
Show resolved Hide resolved
linter_repo: https://github.com/PowerShell/PSScriptAnalyzer
linter_image_url: https://github.com/PowerShell/PSScriptAnalyzer/raw/master/logo.png
linter_rules_configuration_url: https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/using-scriptanalyzer?view=ps-modules#explicit
linter_rules_inline_disable_url: https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/using-scriptanalyzer?view=ps-modules#suppressing-rules
config_file_name: .powershell-psscriptanalyzer.psd1
version_extract_regex: "(\\d+) *(\\d+) *(\\d+)"
examples:
- 'pwsh -NoProfile -NoLogo -Command "Invoke-Formatter -ScriptDefinition ''write-host Hello World''"'
- 'pwsh -NoProfile -NoLogo -Command "Invoke-Formatter -Settings .powershell-psscriptanalyzer.psd1 -ScriptDefinition ''write-host Hello World''"'
# If changing PWSH_VERSION='latest' to a specific version, use format PWSH_VERSION='tags/v7.0.2'
install:
dockerfile:
- ARG PSSA_VERSION='latest'
- RUN pwsh -c 'Install-Module -Name PSScriptAnalyzer -RequiredVersion ${PSSA_VERSION} -Scope AllUsers -Force'
ide:
vscode:
- name: VSCode PowerShell extension
url: https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@
"PHP_PSALM",
"PHP_PHPLINT",
"POWERSHELL_POWERSHELL",
"POWERSHELL_POWERSHELL_FORMATTER",
"PROTOBUF_PROTOLINT",
"PUPPET_PUPPET_LINT",
"PYTHON_PYLINT",
Expand Down
17 changes: 13 additions & 4 deletions megalinter/linters/PowershellLinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,21 @@ def __init__(self, params=None, linter_config=None):

# Build the CLI command to call to lint a file with a powershell script
def build_lint_command(self, file=None):
pwsh_script = ["Invoke-ScriptAnalyzer -EnableExit"]
if self.linter_name == "powershell":
pwsh_script = ["Invoke-ScriptAnalyzer -EnableExit"]
elif self.linter_name == "powershell_formatter":
pwsh_script = ["Invoke-Formatter"]

if self.config_file is not None:
pwsh_script[0] += " -Settings " + self.config_file
pwsh_script[0] += f" -Path '{file}'"
if self.apply_fixes is True and self.cli_lint_fix_arg_name is not None:
pwsh_script[0] += f" {self.cli_lint_fix_arg_name}"

if self.linter_name == "powershell":
pwsh_script[0] += f" -Path '{file}'"
elif self.linter_name == "powershell_formatter":
pwsh_script[0] += f" -ScriptDefinition (Get-Content -Path '{file}' -Raw) > '{file}'"

if self.linter_name == "powershell" and self.apply_fixes is True and self.cli_lint_fix_arg_name is not None:
pwsh_script[0] += f" {self.cli_lint_fix_arg_name}"
cmd = [
self.cli_executable,
"-NoProfile",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# !/usr/bin/env python3
"""
Unit tests for POWERSHELL linter powershell_formatter
This class has been automatically @generated by .automation/build.py, please do not update it manually
"""

from unittest import TestCase

from megalinter.tests.test_megalinter.LinterTestRoot import LinterTestRoot


class powershell_powershell_formatter_test(TestCase, LinterTestRoot):
descriptor_id = "POWERSHELL"
linter_name = "powershell_formatter"