Skip to content

Commit

Permalink
[ci] check PowerShell scripts with PSScriptAnalyzer (part 1) (#6704)
Browse files Browse the repository at this point in the history
* introdure PSScriptAnalyzer

* revert workflow

* run PSScriptAnalyzer before conda installation
  • Loading branch information
StrikerRUS authored Oct 29, 2024
1 parent 4a60a53 commit dc0ed53
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 79 deletions.
56 changes: 56 additions & 0 deletions .ci/lint-powershell.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
$settings = @{
Severity = @(
'Information',
'Warning',
'Error'
)
IncludeDefaultRules = $true
# Additional rules that are disabled by default
Rules = @{
PSAvoidExclaimOperator = @{
Enable = $true
}
PSAvoidLongLines = @{
Enable = $true
MaximumLineLength = 120
}
PSAvoidSemicolonsAsLineTerminators = @{
Enable = $true
}
PSPlaceCloseBrace = @{
Enable = $true
NoEmptyLineBefore = $true
IgnoreOneLineBlock = $true
NewLineAfter = $false
}
PSPlaceOpenBrace = @{
Enable = $true
OnSameLine = $true
NewLineAfter = $true
IgnoreOneLineBlock = $true
}
PSUseConsistentIndentation = @{
Enable = $true
IndentationSize = 4
PipelineIndentation = 'IncreaseIndentationAfterEveryPipeline'
Kind = 'space'
}
PSUseConsistentWhitespace = @{
Enable = $true
CheckInnerBrace = $true
CheckOpenBrace = $true
CheckOpenParen = $true
CheckOperator = $true
CheckSeparator = $true
CheckPipe = $true
CheckPipeForRedundantWhitespace = $true
CheckParameter = $true
IgnoreAssignmentOperatorInsideHashTable = $false
}
PSUseCorrectCasing = @{
Enable = $true
}
}
}

Invoke-ScriptAnalyzer -Path "$env:BUILD_DIRECTORY/.ci" -Recurse -EnableExit -Settings $settings
1 change: 0 additions & 1 deletion .ci/lint-r-code.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

loadNamespace("lintr")

args <- commandArgs(
Expand Down
97 changes: 50 additions & 47 deletions .ci/test-r-package-windows.ps1
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Download a file and retry upon failure. This looks like
# an infinite loop but CI-level timeouts will kill it
function Download-File-With-Retries {
param(
[string]$url,
[string]$destfile
)
$ProgressPreference = "SilentlyContinue" # progress bar bug extremely slows down download speed
do {
Write-Output "Downloading ${url}"
sleep 5;
Invoke-WebRequest -Uri $url -OutFile $destfile
} while(!$?);
function Get-File-With-Tenacity {
param(
[Parameter(Mandatory = $true)][string]$url,
[Parameter(Mandatory = $true)][string]$destfile
)
$ProgressPreference = "SilentlyContinue" # progress bar bug extremely slows down download speed
do {
Write-Output "Downloading ${url}"
sleep 5
Invoke-WebRequest -Uri $url -OutFile $destfile
} while (-not $?)
}

# External utilities like R.exe / Rscript.exe writing to stderr (even for harmless
Expand All @@ -20,20 +20,23 @@ function Download-File-With-Retries {
# Using standard PowerShell redirection does not work to avoid these errors.
# This function uses R's built-in redirection mechanism, sink(). Any place where
# this function is used is a command that writes harmless messages to stderr
function Run-R-Code-Redirect-Stderr {
param(
[string]$rcode
)
$decorated_code = "out_file <- file(tempfile(), open = 'wt'); sink(out_file, type = 'message'); $rcode; sink()"
Rscript --vanilla -e $decorated_code
function Invoke-R-Code-Redirect-Stderr {
param(
[Parameter(Mandatory = $true)][string]$rcode
)
$decorated_code = "out_file <- file(tempfile(), open = 'wt'); sink(out_file, type = 'message'); $rcode; sink()"
Rscript --vanilla -e $decorated_code
}

# Remove all items matching some pattern from PATH environment variable
function Remove-From-Path {
param(
[string]$pattern_to_remove
)
$env:PATH = ($env:PATH.Split(';') | Where-Object { $_ -notmatch "$pattern_to_remove" }) -join ';'
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory = $true)][string]$pattern_to_remove
)
if ($PSCmdlet.ShouldProcess($env:PATH, "Removing ${pattern_to_remove}")) {
$env:PATH = ($env:PATH.Split(';') | Where-Object { $_ -notmatch "$pattern_to_remove" }) -join ';'
}
}

# remove some details that exist in the GitHub Actions images which might
Expand Down Expand Up @@ -87,7 +90,7 @@ if ($env:R_MAJOR_VERSION -eq "3") {
$env:R_WINDOWS_VERSION = "4.3.1"
} else {
Write-Output "[ERROR] Unrecognized R version: $env:R_VERSION"
Check-Output $false
Assert-Output $false
}
$env:CMAKE_VERSION = "3.30.0"

Expand Down Expand Up @@ -120,29 +123,29 @@ tzutil /s "GMT Standard Time"

# download R, RTools and CMake
Write-Output "Downloading R, Rtools and CMake"
Download-File-With-Retries -url "$env:CRAN_MIRROR/bin/windows/base/old/$env:R_WINDOWS_VERSION/R-$env:R_WINDOWS_VERSION-win.exe" -destfile "R-win.exe"
Download-File-With-Retries -url "https://github.com/microsoft/LightGBM/releases/download/v2.0.12/$env:RTOOLS_EXE_FILE" -destfile "Rtools.exe"
Download-File-With-Retries -url "https://github.com/Kitware/CMake/releases/download/v$env:CMAKE_VERSION/cmake-$env:CMAKE_VERSION-windows-x86_64.zip" -destfile "$env:CMAKE_PATH/cmake.zip"
Get-File-With-Tenacity -url "$env:CRAN_MIRROR/bin/windows/base/old/$env:R_WINDOWS_VERSION/R-$env:R_WINDOWS_VERSION-win.exe" -destfile "R-win.exe"
Get-File-With-Tenacity -url "https://github.com/microsoft/LightGBM/releases/download/v2.0.12/$env:RTOOLS_EXE_FILE" -destfile "Rtools.exe"
Get-File-With-Tenacity -url "https://github.com/Kitware/CMake/releases/download/v$env:CMAKE_VERSION/cmake-$env:CMAKE_VERSION-windows-x86_64.zip" -destfile "$env:CMAKE_PATH/cmake.zip"

# Install R
Write-Output "Installing R"
Start-Process -FilePath R-win.exe -NoNewWindow -Wait -ArgumentList "/VERYSILENT /DIR=$env:R_LIB_PATH/R /COMPONENTS=main,x64,i386" ; Check-Output $?
Start-Process -FilePath R-win.exe -NoNewWindow -Wait -ArgumentList "/VERYSILENT /DIR=$env:R_LIB_PATH/R /COMPONENTS=main,x64,i386" ; Assert-Output $?
Write-Output "Done installing R"

Write-Output "Installing Rtools"
Start-Process -FilePath Rtools.exe -NoNewWindow -Wait -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /DIR=$RTOOLS_INSTALL_PATH" ; Check-Output $?
Start-Process -FilePath Rtools.exe -NoNewWindow -Wait -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /DIR=$RTOOLS_INSTALL_PATH" ; Assert-Output $?
Write-Output "Done installing Rtools"

Write-Output "Installing CMake"
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:CMAKE_PATH/cmake.zip", "$env:CMAKE_PATH") ; Check-Output $?
[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:CMAKE_PATH/cmake.zip", "$env:CMAKE_PATH") ; Assert-Output $?
# Remove old CMake shiped with RTools
Remove-Item "$env:RTOOLS_MINGW_BIN/cmake.exe" -Force -ErrorAction Ignore
Write-Output "Done installing CMake"

Write-Output "Installing dependencies"
$packages = "c('data.table', 'jsonlite', 'knitr', 'markdown', 'Matrix', 'processx', 'R6', 'RhpcBLASctl', 'testthat'), dependencies = c('Imports', 'Depends', 'LinkingTo')"
Run-R-Code-Redirect-Stderr "options(install.packages.check.source = 'no'); install.packages($packages, repos = '$env:CRAN_MIRROR', type = 'binary', lib = '$env:R_LIB_PATH', Ncpus = parallel::detectCores())" ; Check-Output $?
Invoke-R-Code-Redirect-Stderr "options(install.packages.check.source = 'no'); install.packages($packages, repos = '$env:CRAN_MIRROR', type = 'binary', lib = '$env:R_LIB_PATH', Ncpus = parallel::detectCores())" ; Assert-Output $?

Write-Output "Building R-package"

Expand All @@ -163,9 +166,9 @@ if ($env:COMPILER -ne "MSVC") {
$env:BUILD_R_FLAGS = "'--skip-install'"
} else {
Write-Output "[ERROR] Unrecognized toolchain: $env:TOOLCHAIN"
Check-Output $false
Assert-Output $false
}
Run-R-Code-Redirect-Stderr "commandArgs <- function(...){$env:BUILD_R_FLAGS}; source('build_r.R')"; Check-Output $?
Invoke-R-Code-Redirect-Stderr "commandArgs <- function(...){$env:BUILD_R_FLAGS}; source('build_r.R')"; Assert-Output $?
} elseif ($env:R_BUILD_TYPE -eq "cran") {
# NOTE: gzip and tar are needed to create a CRAN package on Windows, but
# some flavors of tar.exe can fail in some settings on Windows.
Expand All @@ -174,7 +177,7 @@ if ($env:COMPILER -ne "MSVC") {
if ($env:R_MAJOR_VERSION -eq "3") {
$env:PATH = "C:\msys64\usr\bin;" + $env:PATH
}
Run-R-Code-Redirect-Stderr "result <- processx::run(command = 'sh', args = 'build-cran-package.sh', echo = TRUE, windows_verbatim_args = FALSE, error_on_status = TRUE)" ; Check-Output $?
Invoke-R-Code-Redirect-Stderr "result <- processx::run(command = 'sh', args = 'build-cran-package.sh', echo = TRUE, windows_verbatim_args = FALSE, error_on_status = TRUE)" ; Assert-Output $?
Remove-From-Path ".*msys64.*"
# Test CRAN source .tar.gz in a directory that is not this repo or below it.
# When people install.packages('lightgbm'), they won't have the LightGBM
Expand All @@ -193,31 +196,31 @@ if ($env:COMPILER -ne "MSVC") {
} else {
$check_args = "c('CMD', 'check', '--no-multiarch', '--as-cran', '--run-donttest', '$PKG_FILE_NAME')"
}
Run-R-Code-Redirect-Stderr "result <- processx::run(command = 'R.exe', args = $check_args, echo = TRUE, windows_verbatim_args = FALSE, error_on_status = TRUE)" ; $check_succeeded = $?
Invoke-R-Code-Redirect-Stderr "result <- processx::run(command = 'R.exe', args = $check_args, echo = TRUE, windows_verbatim_args = FALSE, error_on_status = TRUE)" ; $check_succeeded = $?

Write-Output "R CMD check build logs:"
$INSTALL_LOG_FILE_NAME = "lightgbm.Rcheck\00install.out"
Get-Content -Path "$INSTALL_LOG_FILE_NAME"

Check-Output $check_succeeded
Assert-Output $check_succeeded

Write-Output "Looking for issues with R CMD check results"
if (Get-Content "$LOG_FILE_NAME" | Select-String -Pattern "NOTE|WARNING|ERROR" -CaseSensitive -Quiet) {
echo "NOTEs, WARNINGs, or ERRORs have been found by R CMD check"
Check-Output $False
Assert-Output $False
}

} else {
$INSTALL_LOG_FILE_NAME = "$env:BUILD_SOURCESDIRECTORY\00install_out.txt"
Run-R-Code-Redirect-Stderr "source('build_r.R')" 1> $INSTALL_LOG_FILE_NAME ; $install_succeeded = $?
Invoke-R-Code-Redirect-Stderr "source('build_r.R')" 1> $INSTALL_LOG_FILE_NAME ; $install_succeeded = $?
Write-Output "----- build and install logs -----"
Get-Content -Path "$INSTALL_LOG_FILE_NAME"
Write-Output "----- end of build and install logs -----"
Check-Output $install_succeeded
Assert-Output $install_succeeded
# some errors are not raised above, but can be found in the logs
if (Get-Content "$INSTALL_LOG_FILE_NAME" | Select-String -Pattern "ERROR" -CaseSensitive -Quiet) {
echo "ERRORs have been found installing lightgbm"
Check-Output $False
Assert-Output $False
}
}

Expand All @@ -231,7 +234,7 @@ if ($env:TOOLCHAIN -ne "MSVC") {
}
if ($checks_cnt -eq 0) {
Write-Output "Wrong R version was found (expected '$env:R_WINDOWS_VERSION'). Check the build logs."
Check-Output $False
Assert-Output $False
}

# Checking that we actually got the expected compiler. The R-package has some logic
Expand All @@ -241,7 +244,7 @@ if ($env:R_BUILD_TYPE -eq "cmake") {
$checks = Select-String -Path "${INSTALL_LOG_FILE_NAME}" -Pattern "Check for working CXX compiler.*$env:COMPILER"
if ($checks.Matches.length -eq 0) {
Write-Output "The wrong compiler was used. Check the build logs."
Check-Output $False
Assert-Output $False
}
}

Expand All @@ -251,7 +254,7 @@ if (($env:COMPILER -eq "MINGW") -and ($env:R_BUILD_TYPE -eq "cmake")) {
$checks = Select-String -Path "${INSTALL_LOG_FILE_NAME}" -Pattern "Trying to build with.*$env:TOOLCHAIN"
if ($checks.Matches.length -eq 0) {
Write-Output "The wrong toolchain was used. Check the build logs."
Check-Output $False
Assert-Output $False
}
}

Expand All @@ -267,7 +270,7 @@ if ($env:R_BUILD_TYPE -eq "cran") {
}
if ($checks_cnt -eq 0) {
Write-Output "MM_PREFETCH preprocessor definition wasn't used. Check the build logs."
Check-Output $False
Assert-Output $False
}

# Checking that MM_MALLOC preprocessor definition is actually used in CI builds.
Expand All @@ -282,25 +285,25 @@ if ($env:R_BUILD_TYPE -eq "cran") {
}
if ($checks_cnt -eq 0) {
Write-Output "MM_MALLOC preprocessor definition wasn't used. Check the build logs."
Check-Output $False
Assert-Output $False
}

# Checking that OpenMP is actually used in CMake builds.
if ($env:R_BUILD_TYPE -eq "cmake") {
$checks = Select-String -Path "${INSTALL_LOG_FILE_NAME}" -Pattern ".*Found OpenMP: TRUE.*"
if ($checks.Matches.length -eq 0) {
Write-Output "OpenMP wasn't found. Check the build logs."
Check-Output $False
Assert-Output $False
}
}

if ($env:COMPILER -eq "MSVC") {
Write-Output "Running tests with testthat.R"
cd R-package/tests
# NOTE: using Rscript.exe intentionally here, instead of Run-R-Code-Redirect-Stderr,
# because something about the interaction between Run-R-Code-Redirect-Stderr
# NOTE: using Rscript.exe intentionally here, instead of Invoke-R-Code-Redirect-Stderr,
# because something about the interaction between Invoke-R-Code-Redirect-Stderr
# and testthat results in failing tests not exiting with a non-0 exit code.
Rscript.exe --vanilla "testthat.R" ; Check-Output $?
Rscript.exe --vanilla "testthat.R" ; Assert-Output $?
}

Write-Output "No issues were found checking the R-package"
Loading

0 comments on commit dc0ed53

Please sign in to comment.