<commit_before>﻿<#
.SYNOPSIS
  Test the au updating of changed packages, as well as the install and uninstall of those packages.

.DESCRIPTION
  This script uses git to get all the packages that have changed since it diverged from the
  master branch and runs those packages through au updating (only if they are automatic packages),
  tries to install them and also tries to uninstall those packages.
  It also accepts an optional packageName that overrides the check for changed packages.

.PARAMETER packageName
  An optional value accepting a single package name.
  If this variable is not specified, or if it's set to $null it gets the package
  name from changed files.

.PARAMETER type
  An optional variable that can be used to specify which kind of tests that should
  be run.
  If the value is set to 'all' (the default) all tests will be run.

.PARAMETER CleanFiles
  If this variable have been specified the script will clean all
  chocolatey logs, au output files and the nupkg files already existing
  in the repository before running the tests.

.PARAMETER TakeScreenshots
  If this variable have been provided, the script will take a screenshot
  of the user desktop after install/uninstall as well as when the message
  'Failures' have been outputted by the choco executable.

.PARAMETER chocoCommandTimeout
  The timeout that should be passed to choco when installing/uninstalling
  packages (defaults to 600 seconds, or 10 minutes)

.PARAMETER timeoutBeforeScreenshot
  The amount of seconds to sleep after installing/uninstalling a package
  and before taking the screenshot.

.PARAMETER screenShotDir
  The directory to where the scrip should save all taken screenshots.
  (The directory does not need to exist before running the script)

.EXAMPLE
  .\Test-RepoPackage.ps1
#>
param(
  [string]$packageName = $null,
  [ValidateSet('all','update','install','uninstall','none')]
  [string]$type = 'all',
  [switch]$CleanFiles,
  [switch]$TakeScreenshots,
  [int]$chocoCommandTimeout = 600,
  [int]$timeoutBeforeScreenshot = 1,
  [string]$screenShotDir = "$env:TEMP\screenshots"
)

function WriteOutput() {
<#
.SYNOPSIS
  Simple helper function to simplify
  the different output methods we use.
#>
  param(
    [Parameter(ValueFromPipeline = $true)]
    [string]$text,
    [ValidateSet('Error','Warning','ChocoError','ChocoWarning','ChocoInfo','Normal')]
    [string]$type = 'Normal'
  )
   switch -Exact ($type) {
    'Error' { Write-Error $text }
    'Warning' { Write-Warning $text }
    'ChocoError' { Write-Host $text -ForegroundColor Black -BackgroundColor Red }
    'ChocoWarning' { Write-Host $text -ForegroundColor Black -BackgroundColor Yellow }
    'ChocoInfo' { Write-Host $text -ForegroundColor White -BackgroundColor Black }
    Default { Write-Host $text }
  }
}

function WriteChocoOutput() {
<#
.SYNOPSIS
  A simple helper function for processing the output of choco.
  Only meant to handle the colorization of text.
#>
  param(
    [Parameter(ValueFromPipeline = $true)]
    [string]$text
  )
  begin {}
  process {
    switch -Regex ($text) {
      '^\s*ERROR|\s*Failures|^Uninstall may not be silent' { WriteOutput $text -type ChocoError }
      '^\s*WARNING' { WriteOutput $text -type ChocoWarning }
      Default { WriteOutput $text -type ChocoInfo }
    }
  }
  end {}
}

function CleanFiles() {
<#
.SYNOPSIS
  The function responsible for cleaning out temporary
  files before we run the tests.
#>
  param(
    [Parameter(Mandatory = $true)]
    [string]$screenShotDir
  )
  $pathsToClean = @(
    "$env:ChocolateyInstall\logs\*"
    "$env:TEMP\chocolatey\au\*"
    "$PSScriptRoot\..\Update-Force-Test*.md"
  )
  if ($TakeScreenshots) { $pathsToClean += @("$screenShotDir\*") }
  $pathsToClean += Get-ChildItem -Recurse "$PSScriptRoot\.." -Filter "*.nupkg" | select -Expand FullName

  $pathsToClean | % {
    if (Test-Path $_) { rm $_ -Recurse }
  }
}

function GetDependentPackage() {
<#
.SYNOPSIS
  Function responsible for aquiring a meta package(s) dependency.
#>
  param(
    [Parameter(Mandatory = $true)]
    [string]$packageDirectory
  )
  $packageName = $PackageDirectory -split '[\/\\]' | select -last 1
  $nuspecPath = Get-Item "$PackageDirectory\*.nuspec"
  $content = Get-Content -Encoding UTF8 $nuspecPath
  $Matches = $null
  $content | ? { $_ -match "\<dependency.*id=`"(${packageName}.(install|portable|app|commandline))" } | select -First 1 | WriteOutput
  $result = if ($Matches) { $Matches[1].ToLowerInvariant() } else { $null }
  return $result
}

function GetPackagePath() {
<#
.SYNOPSIS
  Gets the full path to the specified package.
#>
  param([string]$packageName)
  if ($packageName -eq $null -or $packageName -eq '') {
    return $null
  }
  $sourcePath = gci "$PSScriptRoot\.." -Recurse -Filter "$packageName.nuspec" | select -First 1 -Expand Directory
  if (!$sourcePath) {
    WriteOutput "No path was found for the package: $packageName" -type Warning
  }
  return $sourcePath
}

function GetPackageSelectQuery() {
  param(
    [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
    $InputObject
  )
  begin { $queries = @() }
  process {
    $queries += $InputObject | select `
      @{Name = 'NuspecPath'; Expression = {Resolve-Path "$_\*.nuspec"}},
      @{Name = 'Directory'; Expression = {Resolve-Path $_}},
      @{Name = 'Name'; Expression = {[System.IO.Path]::GetFileName($_).ToLowerInvariant()}},
      @{Name = 'IsAutomatic'; Expression = {$_ -match 'automatic[\/\\]'}},
      @{Name = 'DependentPackage'; Expression = {GetDependentPackage -packageDirectory $_}}
  }
  end {
    $queries
   }
}

function GetPackagesFromDiff() {
<#
  Gets the changed packages that have changed since the
  latest common ancestor of the current branch, and the specified $diffAgainst branch.

.PARAMETER diffAgainst
  The branch we should run git diff against.
#>
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNull()]
    [string]$diffAgainst
  )
  $paths = git diff "${diffAgainst}..." --name-only | % {
    if ($_.StartsWith('..')) {
      $path = Split-Path -Parent $_
    } else {
      $path = Split-Path -Parent (Resolve-Path -Relative "$PSScriptRoot\..\$_")
    }
    while ($path -and !(Test-Path "$path\*.nuspec")) {
      $path = Split-Path -Parent $path
    }
    if ($path) { $path }
  } | select -Unique

  return $paths | GetPackageSelectQuery
}

function GetPackagesFromName() {
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$packageName
  )
  return Get-ChildItem "$PSScriptRoot\..\" -Recurse -Filter "$packageName.nuspec" | select -Unique -expand Directory | GetPackageSelectQuery
}

function MoveLogFile() {
<#
.SYNOPSIS
  Renames the chocolatey.log file to a file matching the specified packageName and commandType
  so it only contains the necessary log for the current package.<commit_msg>(Test-RepoPackage) Fixed file not found when a file is deleted<commit_after>﻿<#
.SYNOPSIS
  Test the au updating of changed packages, as well as the install and uninstall of those packages.

.DESCRIPTION
  This script uses git to get all the packages that have changed since it diverged from the
  master branch and runs those packages through au updating (only if they are automatic packages),
  tries to install them and also tries to uninstall those packages.
  It also accepts an optional packageName that overrides the check for changed packages.

.PARAMETER packageName
  An optional value accepting a single package name.
  If this variable is not specified, or if it's set to $null it gets the package
  name from changed files.

.PARAMETER type
  An optional variable that can be used to specify which kind of tests that should
  be run.
  If the value is set to 'all' (the default) all tests will be run.

.PARAMETER CleanFiles
  If this variable have been specified the script will clean all
  chocolatey logs, au output files and the nupkg files already existing
  in the repository before running the tests.

.PARAMETER TakeScreenshots
  If this variable have been provided, the script will take a screenshot
  of the user desktop after install/uninstall as well as when the message
  'Failures' have been outputted by the choco executable.

.PARAMETER chocoCommandTimeout
  The timeout that should be passed to choco when installing/uninstalling
  packages (defaults to 600 seconds, or 10 minutes)

.PARAMETER timeoutBeforeScreenshot
  The amount of seconds to sleep after installing/uninstalling a package
  and before taking the screenshot.

.PARAMETER screenShotDir
  The directory to where the scrip should save all taken screenshots.
  (The directory does not need to exist before running the script)

.EXAMPLE
  .\Test-RepoPackage.ps1
#>
param(
  [string]$packageName = $null,
  [ValidateSet('all','update','install','uninstall','none')]
  [string]$type = 'all',
  [switch]$CleanFiles,
  [switch]$TakeScreenshots,
  [int]$chocoCommandTimeout = 600,
  [int]$timeoutBeforeScreenshot = 1,
  [string]$screenShotDir = "$env:TEMP\screenshots"
)

function WriteOutput() {
<#
.SYNOPSIS
  Simple helper function to simplify
  the different output methods we use.
#>
  param(
    [Parameter(ValueFromPipeline = $true)]
    [string]$text,
    [ValidateSet('Error','Warning','ChocoError','ChocoWarning','ChocoInfo','Normal')]
    [string]$type = 'Normal'
  )
   switch -Exact ($type) {
    'Error' { Write-Error $text }
    'Warning' { Write-Warning $text }
    'ChocoError' { Write-Host $text -ForegroundColor Black -BackgroundColor Red }
    'ChocoWarning' { Write-Host $text -ForegroundColor Black -BackgroundColor Yellow }
    'ChocoInfo' { Write-Host $text -ForegroundColor White -BackgroundColor Black }
    Default { Write-Host $text }
  }
}

function WriteChocoOutput() {
<#
.SYNOPSIS
  A simple helper function for processing the output of choco.
  Only meant to handle the colorization of text.
#>
  param(
    [Parameter(ValueFromPipeline = $true)]
    [string]$text
  )
  begin {}
  process {
    switch -Regex ($text) {
      '^\s*ERROR|\s*Failures|^Uninstall may not be silent' { WriteOutput $text -type ChocoError }
      '^\s*WARNING' { WriteOutput $text -type ChocoWarning }
      Default { WriteOutput $text -type ChocoInfo }
    }
  }
  end {}
}

function CleanFiles() {
<#
.SYNOPSIS
  The function responsible for cleaning out temporary
  files before we run the tests.
#>
  param(
    [Parameter(Mandatory = $true)]
    [string]$screenShotDir
  )
  $pathsToClean = @(
    "$env:ChocolateyInstall\logs\*"
    "$env:TEMP\chocolatey\au\*"
    "$PSScriptRoot\..\Update-Force-Test*.md"
  )
  if ($TakeScreenshots) { $pathsToClean += @("$screenShotDir\*") }
  $pathsToClean += Get-ChildItem -Recurse "$PSScriptRoot\.." -Filter "*.nupkg" | select -Expand FullName

  $pathsToClean | % {
    if (Test-Path $_) { rm $_ -Recurse }
  }
}

function GetDependentPackage() {
<#
.SYNOPSIS
  Function responsible for aquiring a meta package(s) dependency.
#>
  param(
    [Parameter(Mandatory = $true)]
    [string]$packageDirectory
  )
  $packageName = $PackageDirectory -split '[\/\\]' | select -last 1
  $nuspecPath = Get-Item "$PackageDirectory\*.nuspec"
  $content = Get-Content -Encoding UTF8 $nuspecPath
  $Matches = $null
  $content | ? { $_ -match "\<dependency.*id=`"(${packageName}.(install|portable|app|commandline))" } | select -First 1 | WriteOutput
  $result = if ($Matches) { $Matches[1].ToLowerInvariant() } else { $null }
  return $result
}

function GetPackagePath() {
<#
.SYNOPSIS
  Gets the full path to the specified package.
#>
  param([string]$packageName)
  if ($packageName -eq $null -or $packageName -eq '') {
    return $null
  }
  $sourcePath = gci "$PSScriptRoot\.." -Recurse -Filter "$packageName.nuspec" | select -First 1 -Expand Directory
  if (!$sourcePath) {
    WriteOutput "No path was found for the package: $packageName" -type Warning
  }
  return $sourcePath
}

function GetPackageSelectQuery() {
  param(
    [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
    $InputObject
  )
  begin { $queries = @() }
  process {
    $queries += $InputObject | select `
      @{Name = 'NuspecPath'; Expression = {Resolve-Path "$_\*.nuspec"}},
      @{Name = 'Directory'; Expression = {Resolve-Path $_}},
      @{Name = 'Name'; Expression = {[System.IO.Path]::GetFileName($_).ToLowerInvariant()}},
      @{Name = 'IsAutomatic'; Expression = {$_ -match 'automatic[\/\\]'}},
      @{Name = 'DependentPackage'; Expression = {GetDependentPackage -packageDirectory $_}}
  }
  end {
    $queries
   }
}

function GetPackagesFromDiff() {
<#
  Gets the changed packages that have changed since the
  latest common ancestor of the current branch, and the specified $diffAgainst branch.

.PARAMETER diffAgainst
  The branch we should run git diff against.
#>
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNull()]
    [string]$diffAgainst
  )
  $paths = git diff "${diffAgainst}..." --name-only | % {
    if ($_.StartsWith('..')) {
      $path = Split-Path -Parent $_
    } else {
      $root = Resolve-Path "$PSScriptRoot\.." -Relative
      $path = Split-Path -Parent "$root\$_"
    }
    while ($path -and !(Test-Path "$path\*.nuspec")) {
      $path = Split-Path -Parent $path
    }
    if ($path) { $path }
  } | select -Unique

  return $paths | GetPackageSelectQuery
}

function GetPackagesFromName() {
  param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$packageName
  )
  return Get-ChildItem "$PSScriptRoot\..\" -Recurse -Filter "$packageName.nuspec" | select -Unique -expand Directory | GetPackageSelectQuery
}

function MoveLogFile() {
<#
.SYNOPSIS
  Renames the chocolatey.log file to a file matching the specified packageName and commandType
  so it only contains the necessary log for the current package.
{'fraction_non_alphanumeric': 0.11769840692514731, 'fraction_numerical': 0.002182294318760457, 'mean_word_length': 3.7276478679504814, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3281960', 'n_tokens_mistral': 4266, 'n_tokens_neox': 4198, 'n_words': 1362}