Skip to content

Commit

Permalink
Lint Community Scripts (microsoft#132425)
Browse files Browse the repository at this point in the history
* Lint Community Scripts

* Fix ScriptAnalyzer warnings and properly justify suppressed items

* Bump Version

* Fix PS7 Analyzer Errors
  • Loading branch information
Trenly authored Jan 2, 2024
1 parent 6107ba3 commit 1fabed4
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 66 deletions.
48 changes: 24 additions & 24 deletions Tools/PRTest.ps1
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
# This script does a checkout of a Pull Request using the GitHub CLI, and then runs it using SandboxTest.ps1.
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'This script is not intended to have any outputs piped')]

Param(
[Parameter(Position = 0, HelpMessage = "The Pull Request to checkout.", Mandatory=$true)]
[String] $PullRequest,
[Parameter(HelpMessage = "Open the Pull Request's review page in the default browser")]
[Switch] $Review = $false,
[Switch] $KeepBranch = $false,
[Switch] $Prerelease = $false,
[Switch] $EnableExperimentalFeatures = $false,
[string] $WinGetVersion = $null
[Parameter(Position = 0, HelpMessage = 'The Pull Request to checkout.', Mandatory = $true)]
[String] $PullRequest,
[Parameter(HelpMessage = "Open the Pull Request's review page in the default browser")]
[Switch] $Review = $false,
[Switch] $KeepBranch = $false,
[Switch] $Prerelease = $false,
[Switch] $EnableExperimentalFeatures = $false,
[string] $WinGetVersion = $null
)

$PullRequest = $PullRequest.TrimStart('#')

$ErrorActionPreference = "Stop"
$ErrorActionPreference = 'Stop'

$repositoryRoot = "https://github.com/microsoft/winget-pkgs/"
$repositoryRoot = 'https://github.com/microsoft/winget-pkgs/'

$rootDirectory = ((Resolve-Path (git rev-parse --show-toplevel)).ToString() + "\")
$rootDirectory = ((Resolve-Path (git rev-parse --show-toplevel)).ToString() + '\')

if (-Not (Get-Command "gh" -ErrorAction "SilentlyContinue")) {
if (-Not (Get-Command 'gh' -ErrorAction 'SilentlyContinue')) {
Write-Host "The GitHub CLI is not installed. Install it via 'winget install GitHub.cli' and come back here!" -ForegroundColor Red
return
}

if (-Not (Get-Command "git" -ErrorAction "SilentlyContinue")) {
if (-Not (Get-Command 'git' -ErrorAction 'SilentlyContinue')) {
Write-Host "Git is not installed. Install it via 'winget install Git.Git' and come back here!" -ForegroundColor Red
return
}

gh pr checkout $PullRequest $(if (!$KeepBranch){'--detach'}) -f | Out-Null
gh pr checkout $PullRequest $(if (!$KeepBranch) { '--detach' }) -f | Out-Null

if($LASTEXITCODE -ne 0) {
if ($LASTEXITCODE -ne 0) {
Write-Host "There was an error checking out the PR. Make sure you're logged into GitHub via 'gh auth login' and come back here!" -ForegroundColor Red
return
}

$manifest = (git diff --name-only HEAD~1..HEAD)
if ($manifest.GetType().Name -eq "Object[]") {
if ($manifest.GetType().Name -eq 'Object[]') {
$path = (Get-Item (Resolve-Path ($rootDirectory + $manifest[0]))).Directory
}
else {
} else {
$path = (Get-Item (Resolve-Path ($rootDirectory + $manifest))).Directory
}

$sandboxTestPath = (Resolve-Path ($PSScriptRoot.ToString() + "\SandboxTest.ps1")).ToString()
$sandboxTestPath = (Resolve-Path ($PSScriptRoot.ToString() + '\SandboxTest.ps1')).ToString()
$params = @{
Manifest = $path
SkipManifestValidation = $true
Prerelease = $Prerelease
Manifest = $path
SkipManifestValidation = $true
Prerelease = $Prerelease
EnableExperimentalFeatures = $EnableExperimentalFeatures
WinGetVersion = $WinGetVersion
WinGetVersion = $WinGetVersion
}
& $sandboxTestPath @params

if ($Review) {
Write-Host "Opening $PullRequest in browser..." -ForegroundColor Green
Start-Process ($repositoryRoot + "pull/" + $PullRequest + "/files")
Start-Process ($repositoryRoot + 'pull/' + $PullRequest + '/files')
}
20 changes: 11 additions & 9 deletions Tools/SandboxTest.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Parse arguments
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'This script is not intended to have any outputs piped')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Prerelease', Justification = 'The variable is used in a conditional but ScriptAnalyser does not recognize the scope')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'WinGetVersion', Justification = 'The variable is used in a conditional but ScriptAnalyser does not recognize the scope')]

Param(
[Parameter(Position = 0, HelpMessage = 'The Manifest to install in the Sandbox.')]
Expand Down Expand Up @@ -79,11 +82,11 @@ $WebClient = New-Object System.Net.WebClient

function Get-Release {
$releasesAPIResponse = Invoke-RestMethod 'https://api.github.com/repos/microsoft/winget-cli/releases?per_page=100'
if (!$Prerelease) {
if (!$script:Prerelease) {
$releasesAPIResponse = $releasesAPIResponse.Where({ !$_.prerelease })
}
if (![String]::IsNullOrWhiteSpace($WinGetVersion)) {
$releasesAPIResponse = @($releasesAPIResponse.Where({ $_.tag_name -match $('^v?' + [regex]::escape($WinGetVersion)) }))
if (![String]::IsNullOrWhiteSpace($script:WinGetVersion)) {
$releasesAPIResponse = @($releasesAPIResponse.Where({ $_.tag_name -match $('^v?' + [regex]::escape($script:WinGetVersion)) }))
}
if ($releasesAPIResponse.Count -lt 1) {
Write-Output 'No WinGet releases found matching criteria'
Expand Down Expand Up @@ -123,15 +126,15 @@ $vcLibsUwp = @{
SaveTo = $(Join-Path $tempFolder -ChildPath 'Microsoft.VCLibs.x64.14.00.Desktop.appx')
}
$uiLibsUwp = @{
url = 'https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.7.3/Microsoft.UI.Xaml.2.7.x64.appx'
hash = '8CE30D92ABEC6522BEB2544E7B716983F5CBA50751B580D89A36048BF4D90316'
SaveTo = $(Join-Path $tempFolder -ChildPath 'Microsoft.UI.Xaml.2.7.x64.appx')
url = 'https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.7.3/Microsoft.UI.Xaml.2.7.x64.appx'
hash = '8CE30D92ABEC6522BEB2544E7B716983F5CBA50751B580D89A36048BF4D90316'
SaveTo = $(Join-Path $tempFolder -ChildPath 'Microsoft.UI.Xaml.2.7.x64.appx')
}

$dependencies = @($desktopAppInstaller, $vcLibsUwp, $uiLibsUwp)

# Clean temp directory
Get-ChildItem $tempFolder -Recurse -Exclude $($(Split-Path $dependencies.SaveTo -Leaf) -replace '\.([^\.]+)$','.*') | Remove-Item -Force -Recurse
Get-ChildItem $tempFolder -Recurse -Exclude $($(Split-Path $dependencies.SaveTo -Leaf) -replace '\.([^\.]+)$', '.*') | Remove-Item -Force -Recurse

if (-Not [String]::IsNullOrWhiteSpace($Manifest)) {
Copy-Item -Path $Manifest -Recurse -Destination $tempFolder
Expand All @@ -156,8 +159,7 @@ foreach ($dependency in $dependencies) {
try {
# If the directory doesn't already exist, create it
$saveDirectory = Split-Path $dependency.SaveTo
if (-Not (Test-Path -Path $saveDirectory))
{
if (-Not (Test-Path -Path $saveDirectory)) {
New-Item -ItemType Directory -Path $saveDirectory -Force | Out-Null
}
$WebClient.DownloadFile($dependency.url, $dependency.SaveTo)
Expand Down
9 changes: 4 additions & 5 deletions Tools/WingetVersionManager.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ if (!$Prerelease) {
}

if ($PSBoundParameters.Keys -contains 'Version') {
$releasesAPIResponse = @($releasesAPIResponse.Where({ $_.tag_name -match $('^v?'+[regex]::escape($Version))}))
$releasesAPIResponse = @($releasesAPIResponse.Where({ $_.tag_name -match $('^v?' + [regex]::escape($Version)) }))
}

if ($Latest) {
Expand All @@ -36,7 +36,7 @@ $msixFileUrl = $assets.Where({ $_.name -eq 'Microsoft.DesktopAppInstaller_8wekyb
$releaseTag = $releasesAPIResponse[0].tag_name
Write-Host "Found $releaseTag"

if ($Clean){
if ($Clean) {
Get-AppxPackage 'Microsoft.DesktopAppInstaller' | Remove-AppxPackage
}

Expand All @@ -57,16 +57,15 @@ foreach ($file in $existingFiles) {
Write-Output 'Found file in local store. Skipping download'
}
}
if (!$msixFile){
if (!$msixFile) {
$outputPath = Join-Path $versionFolder -ChildPath "winget_$releaseTag.msix"
Write-Output "Downloading version $releaseTag to $outputPath"
Invoke-WebRequest -Uri $msixFileUrl -OutFile $outputPath
$file = Get-Item $outputPath
if ((Get-FileHash $file).Hash.ToLower() -ne $sha256) {
Write-Output 'Download failed. Installer hashes do not match.'
exit 1
}
else {
} else {
$msixFile = $file
}
}
Expand Down
61 changes: 33 additions & 28 deletions Tools/YamlCreate.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#Requires -Version 5
#Requires -Version 5
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'This script is not intended to have any outputs piped')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Preserve', Justification = 'The variable is used in a conditional but ScriptAnalyser does not recognize the scope')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', Scope = 'Function', Target = 'Read-AppsAndFeaturesEntries',
Justification = 'Ths function is a wrapper which calls the singular Read-AppsAndFeaturesEntry as many times as necessary. It corresponds exactly to a pluralized manifest field')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', Scope = 'Function', Target = '*Metadata',
Justification = 'Metadata is used as a mass noun and is therefore singular in the cases used in this script')]

Param
(
Expand Down Expand Up @@ -163,7 +168,7 @@ if ($Settings) {
exit
}

$ScriptHeader = '# Created with YamlCreate.ps1 v2.2.12'
$ScriptHeader = '# Created with YamlCreate.ps1 v2.2.13'
$ManifestVersion = '1.5.0'
$PSDefaultParameterValues = @{ '*:Encoding' = 'UTF8' }
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Expand Down Expand Up @@ -460,8 +465,8 @@ Function Request-InstallerUrl {
}
}
}
$NewInstallerUrl = [System.Web.HttpUtility]::UrlDecode($NewInstallerUrl.Replace('+','%2B'))
$NewInstallerUrl = $NewInstallerUrl.Replace(' ','%20')
$NewInstallerUrl = [System.Web.HttpUtility]::UrlDecode($NewInstallerUrl.Replace('+', '%2B'))
$NewInstallerUrl = $NewInstallerUrl.Replace(' ', '%20')
if ($script:_returnValue.StatusCode -ne 409) {
if (Test-String $NewInstallerUrl -MaxLength $Patterns.InstallerUrlMaxLength -MatchPattern $Patterns.InstallerUrl -NotNull) {
$script:_returnValue = [ReturnValue]::Success()
Expand Down Expand Up @@ -601,7 +606,7 @@ Function Get-MsiDatabase {
do {
$_Table = $_TablesView.Fetch()
if ($_Table) {
$_TableName = Get-Property $_Table StringData 1
$_TableName = Get-Property -Object $_Table -PropertyName StringData -ArgumentList 1
$_Database["$_TableName"] = @{}
}
} while ($_Table)
Expand All @@ -614,8 +619,8 @@ Function Get-MsiDatabase {
$_Item = $_ItemView.Fetch()
if ($_Item) {
$_ItemValue = $null
$_ItemName = Get-Property $_Item StringData 1
if ($_Table -eq 'Property') { $_ItemValue = Get-Property $_Item StringData 2 -ErrorAction SilentlyContinue }
$_ItemName = Get-Property -Object $_Item -PropertyName StringData -ArgumentList 1
if ($_Table -eq 'Property') { $_ItemValue = Get-Property -Object $_Item -PropertyName StringData -ArgumentList 2 -ErrorAction SilentlyContinue }
$_Database.$_Table["$_ItemName"] = $_ItemValue
}
} while ($_Item)
Expand Down Expand Up @@ -706,7 +711,7 @@ Function Get-ExeType {
# If the burn header isn't present in the first 264 bytes, scan through the rest of the binary
elseif ($ScriptSettings.IdentifyBurnInstallers -eq 'true') {
$rollingBytes = $bytes[ - $burn.Length..-1]
for ($i = 265; $i -lt ($fileStream.Length,524280|Measure-Object -Minimum).Minimum; $i++) {
for ($i = 265; $i -lt ($fileStream.Length, 524280 | Measure-Object -Minimum).Minimum; $i++) {
$rollingBytes = $rollingBytes[1..$rollingBytes.Length]
$rollingBytes += $reader.ReadByte()
if (($rollingBytes -join '') -match ($burn -join '')) {
Expand Down Expand Up @@ -800,25 +805,23 @@ Function Get-UriScope {
return $null
}

function Get-PublisherHash($publisherName)
{
# Sourced from https://marcinotorowski.com/2021/12/19/calculating-hash-part-of-msix-package-family-name
$publisherNameAsUnicode = [System.Text.Encoding]::Unicode.GetBytes($publisherName);
$publisherSha256 = [System.Security.Cryptography.HashAlgorithm]::Create("SHA256").ComputeHash($publisherNameAsUnicode);
$publisherSha256First8Bytes = $publisherSha256 | Select-Object -First 8;
$publisherSha256AsBinary = $publisherSha256First8Bytes | ForEach-Object { [System.Convert]::ToString($_, 2).PadLeft(8, '0') };
$asBinaryStringWithPadding = [System.String]::Concat($publisherSha256AsBinary).PadRight(65, '0');
function Get-PublisherHash($publisherName) {
# Sourced from https://marcinotorowski.com/2021/12/19/calculating-hash-part-of-msix-package-family-name
$publisherNameAsUnicode = [System.Text.Encoding]::Unicode.GetBytes($publisherName);
$publisherSha256 = [System.Security.Cryptography.HashAlgorithm]::Create('SHA256').ComputeHash($publisherNameAsUnicode);
$publisherSha256First8Bytes = $publisherSha256 | Select-Object -First 8;
$publisherSha256AsBinary = $publisherSha256First8Bytes | ForEach-Object { [System.Convert]::ToString($_, 2).PadLeft(8, '0') };
$asBinaryStringWithPadding = [System.String]::Concat($publisherSha256AsBinary).PadRight(65, '0');

$encodingTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
$encodingTable = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';

$result = "";
for ($i = 0; $i -lt $asBinaryStringWithPadding.Length; $i += 5)
{
$asIndex = [System.Convert]::ToInt32($asBinaryStringWithPadding.Substring($i, 5), 2);
$result += $encodingTable[$asIndex];
}
$result = '';
for ($i = 0; $i -lt $asBinaryStringWithPadding.Length; $i += 5) {
$asIndex = [System.Convert]::ToInt32($asBinaryStringWithPadding.Substring($i, 5), 2);
$result += $encodingTable[$asIndex];
}

return $result.ToLower();
return $result.ToLower();
}

Function Get-PackageFamilyName {
Expand All @@ -832,7 +835,7 @@ Function Get-PackageFamilyName {
# Make the downloaded installer a zip file
$_MSIX = Get-Item $FilePath
$_Zip = Join-Path $_MSIX.Directory.FullName -ChildPath 'MSIX_YamlCreate.zip'
$_ZipFolder = [System.IO.Path]::GetDirectoryName($_ZIp)+ '\' + [System.IO.Path]::GetFileNameWithoutExtension($_Zip)
$_ZipFolder = [System.IO.Path]::GetDirectoryName($_ZIp) + '\' + [System.IO.Path]::GetFileNameWithoutExtension($_Zip)
Copy-Item -Path $_MSIX.FullName -Destination $_Zip
# Progress preference has to be set globally for Expand-Archive
# https://github.com/PowerShell/Microsoft.PowerShell.Archive/issues/77#issuecomment-601947496
Expand All @@ -843,7 +846,7 @@ Function Get-PackageFamilyName {
# Restore the old progress preference
$global:ProgressPreference = $globalPreference
# Package could be a single package or a bundle, so regex search for either of them
$_AppxManifest = Get-ChildItem $_ZipFolder -Recurse -File -Filter '*.xml' | Where-Object {$_.Name -match '^Appx(Bundle)?Manifest.xml$'} | Select-Object -First 1
$_AppxManifest = Get-ChildItem $_ZipFolder -Recurse -File -Filter '*.xml' | Where-Object { $_.Name -match '^Appx(Bundle)?Manifest.xml$' } | Select-Object -First 1
[XML] $_XMLContent = Get-Content $_AppxManifest.FullName -Raw
# The path to the node is different between single package and bundles, this should work to get either
$_Identity = @($_XMLContent.Bundle.Identity) + @($_XMLContent.Package.Identity)
Expand Down Expand Up @@ -956,7 +959,7 @@ Function Read-AppsAndFeaturesEntries {
# TODO: Support Multiple AppsAndFeaturesEntries once WinGet supports it
# For now, only select and retain the first entry
foreach ($_AppsAndFeaturesEntry in @($_Installer.AppsAndFeaturesEntries[0])) {
$_AppsAndFeaturesEntries += Read-AppsAndFeaturesEntry $_AppsAndFeaturesEntry
$_AppsAndFeaturesEntries += Read-AppsAndFeaturesEntry $_AppsAndFeaturesEntry
}
return $_AppsAndFeaturesEntries
}
Expand Down Expand Up @@ -1478,7 +1481,7 @@ Function Read-QuickInstallerEntry {
# If the installer is msix or appx, try getting the new package family name
# If the new package family name can't be found, remove it if it exists
if ($script:dest -match '\.(msix|appx)(bundle){0,1}$') {
$PackageFamilyName= Get-PackageFamilyName $script:dest
$PackageFamilyName = Get-PackageFamilyName $script:dest
if (Test-String $PackageFamilyName -MatchPattern $Patterns.FamilyName) {
$_NewInstaller['PackageFamilyName'] = $PackageFamilyName
} elseif ($_NewInstaller.Keys -contains 'PackageFamilyName') {
Expand Down Expand Up @@ -1536,6 +1539,8 @@ Function Read-InstallerMetadataValue {
# If a key does not exist, it sets the value to a special character to be removed / commented later
# Returns the result as a new object
Function Restore-YamlKeyOrder {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'InputObject', Justification = 'The variable is used inside a conditional but ScriptAnalyser does not recognize the scope')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'NoComments', Justification = 'The variable is used inside a conditional but ScriptAnalyser does not recognize the scope')]
Param
(
[Parameter(Mandatory = $true, Position = 0)]
Expand Down

0 comments on commit 1fabed4

Please sign in to comment.