From b22f30438d0cdea6cf1155e07b4cbf66d5eed827 Mon Sep 17 00:00:00 2001 From: Tobi Steenbakkers Date: Wed, 6 Jun 2018 23:14:42 +0200 Subject: [PATCH] Bugfixes, Wrappers, CI/CD and Test Automation (#5) So I reworked the module to enable CI/CD: Added Invoke-Build, BuildHelpers, PlatyPS, Pester and PSScriptanalyzer. I wrote Pester tests for all functionality except the two Invoke functions. (which will be in the next iteration). Because of these changes i had to re-arrange the Module which will BREAK existing installations. I'm sorry for that but this will make sure the future of this repo will be ensured. Also wrote some wrappers for calling functions and generally improved the coding quality because of Pester. --- .gitattributes | 63 ++ Example/CICD-Kicker.ps1 | 2 +- MSSQL-CICD-Helper.build.ps1 | 1 + MSSQL-CICD-Helper/MSSQL-CICD-Helper.psd1 | 2 +- .../Private/BuildDeploy/Invoke-Cmd.ps1 | 121 +++ .../Private/Configuration/ImportConfig.ps1 | 2 +- .../Get-MSSQLCICDHelperFiletoBuildDeploy.ps1 | 11 +- .../Invoke-MSSQLCICDHelperMSBuild.ps1 | 69 +- .../Invoke-MSSQLCICDHelperSQLPackage.ps1 | 68 +- .../Get-MSSQLCICDHelperConfiguration.ps1 | 5 +- .../Get-MSSQLCICDHelperPaths.ps1 | 22 +- .../Save-MSSQLCICDHelperConfiguration.ps1 | 10 +- README.md | 13 + Tests/MSSQL-CICD-Helper.Module.Tests.ps1 | 55 ++ Tests/Unit.Tests.ps1 | 935 ++++++++++++++++++ build.ps1 | 2 +- localpester.ps1 | 45 + 17 files changed, 1358 insertions(+), 68 deletions(-) create mode 100644 .gitattributes create mode 100644 MSSQL-CICD-Helper/Private/BuildDeploy/Invoke-Cmd.ps1 create mode 100644 Tests/MSSQL-CICD-Helper.Module.Tests.ps1 create mode 100644 Tests/Unit.Tests.ps1 create mode 100644 localpester.ps1 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/Example/CICD-Kicker.ps1 b/Example/CICD-Kicker.ps1 index 40256ab..f7f997c 100644 --- a/Example/CICD-Kicker.ps1 +++ b/Example/CICD-Kicker.ps1 @@ -23,7 +23,7 @@ if(-not(Get-Module MSSQLCICDHelper)){ } catch{ write-error "something wnet wrong cloning or importing the MSSQL-CICD-helper module. please check and retry" - exit 1; + Throw; } diff --git a/MSSQL-CICD-Helper.build.ps1 b/MSSQL-CICD-Helper.build.ps1 index 2a89417..d28dbb3 100644 --- a/MSSQL-CICD-Helper.build.ps1 +++ b/MSSQL-CICD-Helper.build.ps1 @@ -15,6 +15,7 @@ function TaskX($Name, $Parameters) {task $Name @Parameters -Source $MyInvocation Task Default Clean, Build, Pester, UpdateSource Task Build CopyToOutput, BuildPSM1, BuildPSD1 Task Pester Build, ImportModule, UnitTests, FullTests +Task LocalPester Build, ImportModule, UnitTests Task Local Build, Pester, UpdateSource Task Clean { diff --git a/MSSQL-CICD-Helper/MSSQL-CICD-Helper.psd1 b/MSSQL-CICD-Helper/MSSQL-CICD-Helper.psd1 index 8eec187..0a60cb1 100644 --- a/MSSQL-CICD-Helper/MSSQL-CICD-Helper.psd1 +++ b/MSSQL-CICD-Helper/MSSQL-CICD-Helper.psd1 @@ -1,5 +1,5 @@ # -# Module manifest for module 'MSSQLCICDHelper' +# Module manifest for module 'MSSQL-CICD-Helper' # # Generated by: Tobi Steenbakkers # diff --git a/MSSQL-CICD-Helper/Private/BuildDeploy/Invoke-Cmd.ps1 b/MSSQL-CICD-Helper/Private/BuildDeploy/Invoke-Cmd.ps1 new file mode 100644 index 0000000..716569b --- /dev/null +++ b/MSSQL-CICD-Helper/Private/BuildDeploy/Invoke-Cmd.ps1 @@ -0,0 +1,121 @@ +function Invoke-Cmd { + <# + .SYNOPSIS + Executes a Invoke-Expression / CMD.Exe based on the Given Parameters. Allows for re-using part of program code and mocking + + .DESCRIPTION + + + .PARAMETER Executable + + + .PARAMETER Arguments + Specifies the Arguments for which the Invoked Cmd should use. + + .PARAMETER logfile + Specifies the Arguments for which the Invoked Cmd should use. + + .PARAMETER errorlogfile + Specifies the Arguments for which the Invoked Cmd should use. + + .OUTPUTS + A result set with the outcome of the process along with some metrics. + + .EXAMPLE + Invoke-Cmd -Arguments + + Will execute the following command: + + .LINK + Project home: https://github.com/tsteenbakkers/MSSQL-CICD-Helper + + .NOTES + Name: MSSQLCICDHelper + Author: Tobi Steenbakkers + Version: 1.0.0 + #> + [cmdletbinding()] + param( + [Parameter(Mandatory=$true, + HelpMessage='What to find: *.sln, *.dacpac, *.publish.xml *.dtspac or *.sqlproject File. Options are: Solution, DacPac, DTSPac or Project', + Position=0)] + [ValidateNotNullOrEmpty()] + $executable, + + [Parameter(Mandatory=$true, + HelpMessage='Path where search for $typetofind should be started', + Position=0)] + [ValidateNotNullOrEmpty()] + $arguments, + + [Parameter(Mandatory=$true, + HelpMessage='Determines the basepath where logfiles should be stored. if empty the directory where the script is running will be used', + Position=0)] + [Alias("lf")] + [ValidateNotNullOrEmpty()] + [String] $logfile, + + [Parameter(Mandatory=$true, + HelpMessage='Determines the basepath where logfiles should be stored. if empty the directory where the script is running will be used', + Position=0)] + [Alias("elf")] + [ValidateNotNullOrEmpty()] + [String] $errorlogfile + ) + $poutput = @{} + $poutput.Output = [string]::Empty + $poutput.ErrorOutput = [string]::Empty + $poutput.Message = [string]::Empty + $poutput.Duration = [TimeSpan]::Zero + $poutput.Succeeded = $null + $poutput.ExitCode = $null + + $logbase = Split-Path -path $logfile -Parent + $errorlogbase = Split-Path -path $logfile -Parent + + if(-not(Test-Path -Path $logbase) -or -not(Test-Path -Path $errorlogbase)){ + + $poutput.Message = "Could not find parent of $logfile or $errorlogfile unable to proceed to execute Cmd." + + Write-Error "$($poutput.message)" + return $result + throw; + } + + try{ + + $pinfo = New-Object System.Diagnostics.ProcessStartInfo + $pinfo.FileName = $executable + $pinfo.Arguments = $arguments + + #$pinfo.Passthru = $true + $pinfo.RedirectStandardError = $true + $pinfo.RedirectStandardOutput = $true + $pinfo.UseShellExecute = $false + + if($debug){ + $pinfo + } + #executing the command and storing the result inside $p: + $p = New-Object System.Diagnostics.Process + $p.StartInfo = $pinfo + $p.Start() | Out-Null + + $poutput.output = $p.StandardOutput.ReadToEnd() + $poutput.erroroutput = $p.StandardError.read() + $poutput.Duration = $p.ExitTime - $p.StartTime + $poutput.output | Out-file -literalpath $logfile -Force + $poutput.erroroutput | Out-file -literalpath $errorlogfile -Force + $poutput.ExitCode = $p.ExitCode + + return $poutput + + }catch{ + $errorMessage = $_ + $poutput.Message = "Unexpected error occurred while processing : $errorMessage" + $poutput.Succeeded = $false + Write-Error ($poutput.Message) + return $poutput + throw; + } +} \ No newline at end of file diff --git a/MSSQL-CICD-Helper/Private/Configuration/ImportConfig.ps1 b/MSSQL-CICD-Helper/Private/Configuration/ImportConfig.ps1 index f259d31..b7f47a2 100644 --- a/MSSQL-CICD-Helper/Private/Configuration/ImportConfig.ps1 +++ b/MSSQL-CICD-Helper/Private/Configuration/ImportConfig.ps1 @@ -30,6 +30,6 @@ Function ImportConfig { } else { Write-Warning 'No saved configuration information found. Run Save-MSSQL-CICD-HelperConfiguration.' Write-Warning "path which was looked for: $configfile" - EXIT 1; + throw; } } diff --git a/MSSQL-CICD-Helper/Public/BuildDeploy/Get-MSSQLCICDHelperFiletoBuildDeploy.ps1 b/MSSQL-CICD-Helper/Public/BuildDeploy/Get-MSSQLCICDHelperFiletoBuildDeploy.ps1 index 05ee54c..d8475fd 100644 --- a/MSSQL-CICD-Helper/Public/BuildDeploy/Get-MSSQLCICDHelperFiletoBuildDeploy.ps1 +++ b/MSSQL-CICD-Helper/Public/BuildDeploy/Get-MSSQLCICDHelperFiletoBuildDeploy.ps1 @@ -36,7 +36,7 @@ function Get-MSSQLCICDHelperFiletoBuildDeploy { [cmdletbinding()] param( [Parameter(Mandatory=$true, - HelpMessage='What to find: *.sln, *.dacpac, *.publish.xml *.dtspac or *.sqlproject File. Options are: Solution, DacPac, DTSPack or Project', + HelpMessage='What to find: *.sln, *.dacpac, *.publish.xml *.dtspac or *.sqlproject File. Options are: Solution, DacPac, DTSPac or Project', Position=0)] [ValidateNotNullOrEmpty()] $typetofind, @@ -66,17 +66,22 @@ function Get-MSSQLCICDHelperFiletoBuildDeploy { } default { Write-Error "Invalid option given for input param -typetofind. valid options are: Solution, Project, dacpac, PublishProfile or dtspac" - EXIT 1; + throw; } } + if(-not(Test-Path $rootpath)){ + Write-Error "$rootpath was not found" + throw; + } + $results = Get-ChildItem -Path $rootpath -Filter $buildfilextension -Recurse -ErrorAction SilentlyContinue Write-Verbose "Found $($results.Count) $buildfilextension files in $rootpath" if($results.Count -lt 1){ Write-Error 'No Files found! Please check path and re-run Get-MSSQLCICDHelperFiletoBuild. Exiting' - EXIT 1; + throw; } elseif($results.Count -gt 1){ Write-Verbose 'Found multiple files. will return the file with the most recent writedatetime.' diff --git a/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperMSBuild.ps1 b/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperMSBuild.ps1 index 440cc0f..280abf2 100644 --- a/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperMSBuild.ps1 +++ b/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperMSBuild.ps1 @@ -183,7 +183,7 @@ function Invoke-MSSQLCICDHelperMSBuild { if($UseInvokeMSBuildModule){ if(-not(Get-Module Invoke-MSBuild)){ Write-Error 'Invoke-MSBuild was not found on this system. Make sure it is installed with Install-Module Invoke-MSBuild' - break; + throw; } } @@ -197,7 +197,13 @@ function Invoke-MSSQLCICDHelperMSBuild { $filename = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind 'Solution' -RootPath $curdir | Get-ChildItem } else{ - $filename = Get-ChildItem $filename + if(-not(Test-Path $filename)){ + Write-Error "File $filename not found." + throw; + }else{ + $filename = Get-ChildItem $filename + } + } Write-Verbose "The following file will be built: $($filename.Name) located in path $($filename.DirectoryName)" @@ -206,7 +212,9 @@ function Invoke-MSSQLCICDHelperMSBuild { $logbase = Split-Path -path $logfile -Parent $result.BuildLogFilePath = $logbase $result.BuildLogFile = $logfile - $result.FiletoBuild = $filename.FullName + $result.FiletoBuild = $filename.FullName + $processlogfile = "$($filename.FullName).msbuildlog.log" + $processerrorlogfile = "$($filename.FullName).msbuilderrorlog.log" Write-Verbose "The following build arguments will be used: $MSBuildArguments" $configfile['MSBuildExe'] @@ -222,19 +230,30 @@ function Invoke-MSSQLCICDHelperMSBuild { #Write-Verbose "Command to be Executed is: cmd.exe $commandtoexecute" $result.CommandUsedToBuild = "Command to be Executed is: cmd.exe $commandtoexecute" - if($hidden){ - Write-verbose "Starting MSBuild ..." - $result.MsBuildProcess = Start-Process cmd.exe -ArgumentList $CommandtoExecute -Wait -WindowStyle Hidden -PassThru - }else{ - Write-verbose "Starting MSBuild ..." - $result.MsBuildProcess = Start-Process cmd.exe -ArgumentList $CommandtoExecute -Wait -NoNewWindow -PassThru - } + $processoutput = Invoke-Cmd -executable 'cmd.exe' -arguments $CommandtoExecute -logfile $processlogfile -errorlogfile $processerrorlogfile + + if(!$hidden){ + "Normal Output: " + $processoutput.output + "Error Output:" + $processoutput.erroroutput + } + # if($hidden){ + # Write-verbose "Starting MSBuild ..." + # $result.MsBuildProcess = Start-Process cmd.exe -ArgumentList $CommandtoExecute -Wait -WindowStyle Hidden -PassThru + # }else{ + # Write-verbose "Starting MSBuild ..." + # $result.MsBuildProcess = Start-Process cmd.exe -ArgumentList $CommandtoExecute -Wait -NoNewWindow -PassThru + # } }else{ $CommandtoExecute = "Invoke-MSBuild -Path $($filename.FullName) -logdirectory $($logbase)" $CommandtoExecute += " -KeepBuildLogOnSuccessfulBuilds" - $CommandtoExecute += " -MsBuildParameters ""$($MSBuildArguments)""" + if($MSBuildArguments){ + + $CommandtoExecute += " -MsBuildParameters ""$($MSBuildArguments)""" + } if ($InvokeMSBuildParameters){ $CommandtoExecute += " $($InvokeMSBuildParameters)" @@ -242,7 +261,17 @@ function Invoke-MSSQLCICDHelperMSBuild { $result.CommandUsedToBuild = "Command to be Executed is: $commandtoexecute" Write-verbose "Starting MSBuild ..." - $result.MsBuildProcess = Invoke-Expression $CommandtoExecute + + $processoutput = Invoke-Cmd -executable 'powershell.exe' -arguments $CommandtoExecute -logfile $processlogfile -errorlogfile $processerrorlogfile + + if(!$hidden){ + "Normal Output: " + $processoutput.output + "Error Output:" + $processoutput.erroroutput + } + + #$result.MsBuildProcess = Invoke-Expression $CommandtoExecute } }catch{ $errorMessage = $_ @@ -250,7 +279,7 @@ function Invoke-MSSQLCICDHelperMSBuild { $result.BuildSucceeded = $false Write-Error ($result.Message) return $result - EXIT 1; + throw; } Write-verbose "MSBuild Started. Continue Checking results..." @@ -262,15 +291,17 @@ function Invoke-MSSQLCICDHelperMSBuild { Write-Error "$($result.message)" return $result - EXIT 1; + throw; } if($UseInvokeMSBuildModule){ - [bool] $buildReturnedSuccessfulExitCode = $result.MsBuildProcess.MsBuildProcess.ExitCode -eq 0 - $result.BuildDuration = $result.MsBuildProcess.MsBuildProcess.ExitTime - $result.MsBuildProcess.MsBuildProcess.StartTime + # [bool] $buildReturnedSuccessfulExitCode = $result.MsBuildProcess.MsBuildProcess.ExitCode -eq 0 + # $result.BuildDuration = $result.MsBuildProcess.MsBuildProcess.ExitTime - $result.MsBuildProcess.MsBuildProcess.StartTime + [bool] $buildReturnedSuccessfulExitCode = $processoutput.ExitCode -eq 0 + $result.BuildDuration = $processoutput.Duration }else{ - [bool] $buildReturnedSuccessfulExitCode = $result.MsBuildProcess.ExitCode -eq 0 - $result.BuildDuration = $result.MsBuildProcess.ExitTime - $result.MsBuildProcess.StartTime + [bool] $buildReturnedSuccessfulExitCode = $processoutput.ExitCode -eq 0 + $result.BuildDuration = $processoutput.Duration } [bool] $buildOutputDoesNotContainFailureMessage = (Select-String -Path $($result.BuildLogFile) -Pattern "Build FAILED." -SimpleMatch) -eq $null @@ -294,7 +325,7 @@ function Invoke-MSSQLCICDHelperMSBuild { $result.Message = "Building ""$($result.FiletoBuild)"" Failed! Please check ""$($result.BuildLogFile)"" " Write-Error "$($result.message)" return $result - EXIT 1; + throw; } Write-Verbose "MSBuild passed. See results below..." diff --git a/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperSQLPackage.ps1 b/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperSQLPackage.ps1 index 4ed2c82..6c29b7a 100644 --- a/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperSQLPackage.ps1 +++ b/MSSQL-CICD-Helper/Public/BuildDeploy/Invoke-MSSQLCICDHelperSQLPackage.ps1 @@ -330,7 +330,7 @@ function Invoke-MSSQLCICDHelperSQLPackage { }else{ Write-Error "Some of the target Credentials are not filled" - exit 1; + throw; } } @@ -352,29 +352,30 @@ function Invoke-MSSQLCICDHelperSQLPackage { Write-Verbose "The following Arguments will be used: $shownarguments" $result.CommandUsed = "cmd.exe $shownarguments" - #constructing the process and the arguments to send: - $pinfo = New-Object System.Diagnostics.ProcessStartInfo - $pinfo.FileName = "cmd.exe" - $pinfo.Arguments = $arguments + $processoutput = Invoke-Cmd -executable 'cmd.exe' -Arguments $arguments -logfile $result.LogFile -errorlogfile $result.ErrorLogFile + # #constructing the process and the arguments to send: + # $pinfo = New-Object System.Diagnostics.ProcessStartInfo + # $pinfo.FileName = "cmd.exe" + # $pinfo.Arguments = $arguments - #$pinfo.Passthru = $true - $pinfo.RedirectStandardError = $true - $pinfo.RedirectStandardOutput = $true - $pinfo.UseShellExecute = $false - - if($debug){ - $pinfo - } - #executing the command and storing the result inside $p: - $p = New-Object System.Diagnostics.Process - $p.StartInfo = $pinfo - $p.Start() | Out-Null - - $output = $p.StandardOutput.ReadToEnd() - $erroroutput = $p.StandardError.read() - $result.Duration = $p.ExitTime - $p.StartTime - $output | Out-file -literalpath $logfile -Force - $erroroutput | Out-file -literalpath $errorlogfile -Force + # #$pinfo.Passthru = $true + # $pinfo.RedirectStandardError = $true + # $pinfo.RedirectStandardOutput = $true + # $pinfo.UseShellExecute = $false + + # if($debug){ + # $pinfo + # } + # #executing the command and storing the result inside $p: + # $p = New-Object System.Diagnostics.Process + # $p.StartInfo = $pinfo + # $p.Start() | Out-Null + + # $output = $p.StandardOutput.ReadToEnd() + # $erroroutput = $p.StandardError.read() + # $result.Duration = $p.ExitTime - $p.StartTime + # $output | Out-file -literalpath $logfile -Force + # $erroroutput | Out-file -literalpath $errorlogfile -Force }catch{ @@ -383,14 +384,15 @@ function Invoke-MSSQLCICDHelperSQLPackage { $result.Succeeded = $false Write-Error ($result.Message) return $result - EXIT 1; + throw; } Write-verbose "SQLPackage.exe Started. Continue Checking results..." if(!$hidden){ - - $output - + "Normal Output: " + $processoutput.output + "Error Output:" + $processoutput.erroroutput } @@ -400,11 +402,11 @@ function Invoke-MSSQLCICDHelperSQLPackage { Write-Error "$($result.message)" return $result - EXIT 1; + throw; } - [bool] $ProcessReturnedSuccessfulExitCode = $p.ExitCode -eq 0 + [bool] $ProcessReturnedSuccessfulExitCode = $processoutput.ExitCode -eq 0 [bool] $ProcessOutputDoesNotContainFailureMessage = (((Select-String -Path $($result.LogFile) -Pattern "Could not deploy package" -SimpleMatch) -eq $null) -or ((Select-String -Path $($result.LogFile) -Pattern "Initializing deployment (Failed)" -SimpleMatch) -eq $null)) [bool] $ProcessOutputDoesContainSuccesseMessage = (Select-String -Path $($result.LogFile) -Pattern "Successfully published database." -SimpleMatch -Quiet) -eq $true @@ -414,14 +416,15 @@ function Invoke-MSSQLCICDHelperSQLPackage { $result.Succeeded = $true $result.Message = "command executed Successfully" + $result.Duration = $processoutput.Duration if (!$keeplogfiles) { if (Test-Path $($result.LogFile) -PathType Leaf) { Remove-Item -Path $($result.LogFile) -Force } if (Test-Path $($result.ErrorLogFile) -PathType Leaf) { Remove-Item -Path $($result.ErrorLogFile) -Force } - $result.LogFile = $null - $result.ErrorLogFile = $null + $result.LogFile = 'Deleted' + $result.ErrorLogFile = 'Deleted' } @@ -429,9 +432,10 @@ function Invoke-MSSQLCICDHelperSQLPackage { $result.Succeeded = $false $result.Message = "Processing ""$($result.FiletoProcess)"" Failed! Please check ""$($result.LogFile)"" " + $result.Duration = $processoutput.Duration $result Write-Error "$($result.message)" - EXIT 1; + throw; } diff --git a/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperConfiguration.ps1 b/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperConfiguration.ps1 index eaff9f0..c169d97 100644 --- a/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperConfiguration.ps1 +++ b/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperConfiguration.ps1 @@ -25,11 +25,12 @@ function Get-MSSQLCICDHelperConfiguration { try{ $ConfigFile = ImportConfig - Write-Output $ConfigFile + #Write-Output $ConfigFile + return $ConfigFile }catch{ Write-Error "Could not import config. Make sure it exists or save a new config." - EXIT 1 + throw; } } diff --git a/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperPaths.ps1 b/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperPaths.ps1 index f868d43..0d8f723 100644 --- a/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperPaths.ps1 +++ b/MSSQL-CICD-Helper/Public/Configuration/Get-MSSQLCICDHelperPaths.ps1 @@ -62,6 +62,7 @@ Function Get-MSSQLCICDHelperPaths { ) $exestofind = @() + $results = @() switch($typetofind){ "MSBuild"{ @@ -76,14 +77,29 @@ Function Get-MSSQLCICDHelperPaths { } default { Write-Error "Invalid option given for input param -typetofind. valid options are: MSBuild, SQLPackage or Both" - EXIT 1 + throw; } } + + if(-not(Test-Path $rootpath)){ + + Write-Error "$rootpath was not found." + throw; + } + Write-verbose "searching for $exestofind in $rootpath" + $exestofind | ForEach-Object{ $results += Get-ChildItem -Path $rootpath -filter $_ -Recurse -ErrorAction SilentlyContinue } - Write-Output 'Found the following full paths for given parameters. Please take note of these and use the desired path in Save-MSSQLCICDHelperConfiguration' - $results.FullName + + if($results.Count -lt 1){ + Write-Error 'No Files found! Please check path and re-run. Exiting' + throw; + }Else{ + Write-verbose 'Found the following full paths for given parameters. Please take note of these and use the desired path in Save-MSSQLCICDHelperConfiguration' + $results.FullName + } + } \ No newline at end of file diff --git a/MSSQL-CICD-Helper/Public/Configuration/Save-MSSQLCICDHelperConfiguration.ps1 b/MSSQL-CICD-Helper/Public/Configuration/Save-MSSQLCICDHelperConfiguration.ps1 index ea6ca31..5c69af3 100644 --- a/MSSQL-CICD-Helper/Public/Configuration/Save-MSSQLCICDHelperConfiguration.ps1 +++ b/MSSQL-CICD-Helper/Public/Configuration/Save-MSSQLCICDHelperConfiguration.ps1 @@ -87,8 +87,9 @@ Function Save-MSSQLCICDHelperConfiguration { # testing if either path exists $paths.Keys | ForEach-Object { if(-not(Test-Path ($paths[$_]) ) ) { - Write-Error "Directory for either MSBuild or SQlPackage was not found. Please rerun Save-MSSQLCICDHelperConfiguration with a correct path" - break; + Write-Error "Directory: $($paths[$_]) did not contain either Msbuild or SqlPackage. Please rerun Save-MSSQLCICDHelperConfiguration with a correct path" + + throw; } } @@ -125,7 +126,7 @@ Function Save-MSSQLCICDHelperConfiguration { } else { Write-Error "Unknown Platform" - EXIT 1; + throw; } Write-Verbose 'Testing config path.' @@ -133,8 +134,7 @@ Function Save-MSSQLCICDHelperConfiguration { New-Item -ItemType Directory -Path (Split-Path $ConfigFile) | Out-Null }else{ - Write-error "Path not found" - EXIT 1; + Write-Verbose "Path $ConfigFile found. Overwriting existing file." } $Parameters | Export-Clixml -Path $ConfigFile diff --git a/README.md b/README.md index 75014d3..27715e2 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,30 @@ [![forks badge]][forks] [![issues badge]][issues] +## Dev Build + +[![devbuild badge]][devbuild] + +## Master Build + +[![masterbuild badge]][masterbuild] + [licence badge]:https://img.shields.io/badge/license-MIT-blue.svg [stars badge]:https://img.shields.io/github/stars/tsteenbakkers/MSSQL-CICD-Helper.svg [forks badge]:https://img.shields.io/github/forks/tsteenbakkers/MSSQL-CICD-Helper.svg [issues badge]:https://img.shields.io/github/issues/tsteenbakkers/MSSQL-CICD-Helper.svg [release badge]:https://img.shields.io/github/release/tsteenbakkers/MSSQL-CICD-Helper.svg +[devbuild badge]:https://ci.appveyor.com/api/projects/status/l7vbq4q6x86rgmtd?svg=true&branch=DEV +[masterbuild badge]:https://ci.appveyor.com/api/projects/status/l7vbq4q6x86rgmtd?svg=true&branch=master + [licence]:https://github.com/tsteenbakkers/MSSQL-CICD-Helper/blob/master/LICENSE.md [stars]:https://github.com/tsteenbakkers/MSSQL-CICD-Helper/stargazers [forks]:https://github.com/tsteenbakkers/MSSQL-CICD-Helper/network [issues]:https://github.com/tsteenbakkers/MSSQL-CICD-Helper/issues [release]:https://github.com/tsteenbakkers/MSSQL-CICD-Helper/releases +[devbuild]:https://ci.appveyor.com/api/projects/status/l7vbq4q6x86rgmtd?branch=DEV +[masterbuild]:https://ci.appveyor.com/api/projects/status/l7vbq4q6x86rgmtd?branch=master - [Introduction](#introduction) - [Support / Contribution](#support--contribution) diff --git a/Tests/MSSQL-CICD-Helper.Module.Tests.ps1 b/Tests/MSSQL-CICD-Helper.Module.Tests.ps1 new file mode 100644 index 0000000..8cead3c --- /dev/null +++ b/Tests/MSSQL-CICD-Helper.Module.Tests.ps1 @@ -0,0 +1,55 @@ +$ModuleName = Split-Path (Resolve-Path "$PSScriptRoot\..\" ) -Leaf +$ModuleManifest = Resolve-Path "$PSScriptRoot\..\$ModuleName\$ModuleName.psd1" + +#Get-Module $ModuleName | Remove-Module + +#Import-Module $ModuleManifest + +Describe 'Module Information' { + + $ModuleManifest = "$PSScriptRoot\..\MSSQL-CICD-Helper\MSSQL-CICD-Helper.psd1" + + Context 'Module Manifest' { + $Script:Manifest = $null + It 'Valid Manifest File' { + { + $Script:Manifest = Test-ModuleManifest -Path $ModuleManifest -ErrorAction Stop -WarningAction SilentlyContinue + } | Should Not Throw + } + + It 'Valid Manifest Root Module' { + $Script:Manifest.RootModule | Should Be 'MSSQL-CICD-Helper.psm1' + } + + It 'Valid Manifest Name' { + $Script:Manifest.Name | Should be MSSQL-CICD-Helper + } + + It 'Valid Manifest GUID' { + $Script:Manifest.Guid | SHould be '2287837f-86ec-43ef-97a8-fee9f33a7c33' + } + + It 'Valid Author' { + $Script:Manifest.Author | SHould be 'Tobi Steenbakkers' + } + + It 'Valid Manifest Version' { + $Script:Manifest.Version -as [Version] | Should Not BeNullOrEmpty + } + + It 'Valid Manifest Description' { + $Script:Manifest.Description | Should Not BeNullOrEmpty + } + + It 'Required Modules' { + $Script:Manifest.RequiredModules | Should BeNullOrEmpty + } + + It 'Non blank description' { + $Script:Manifest.Description | Should not Benullorempty + } + + } +} + +#Remove-Module $ModuleName diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 new file mode 100644 index 0000000..0e7ce8b --- /dev/null +++ b/Tests/Unit.Tests.ps1 @@ -0,0 +1,935 @@ +$projectRoot = Resolve-Path "$PSScriptRoot\.." +$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") +$moduleName = Split-Path $moduleRoot -Leaf +$testRoot = Resolve-Path "$projectRoot\Tests" + +#Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force +InModuleScope MSSQL-CICD-Helper { + + Describe "CurrentVersion" -Tags Build { + $returnedversion = 'V1.0.0' + + Mock CurrentVersion {$returnedversion} + + It "Saves the configuration with expected values"{ + # Act + $version = currentversion + + # Assert + $version | should be 'v1.0.0' + Assert-MockCalled currentversion -Exactly 1 -Scope It + } + } + + Describe 'Save-MSSQLCICDHelperConfiguration' -Tags Build { + + # Prepare + $FilePath = "$TestDrive\PesterTest.xml" + + $ExportCLIXML = Get-Command Export-Clixml + $currentversion = currentversion + + Mock Export-Clixml { + & $ExportCLIXML -InputObject $InputObject -Path $FilePath + } + + Mock Test-Path {$true} + + It "Saves the configuration with expected values"{ + # Act + Save-MSSQLCICDHelperConfiguration -SQLPackageExePath 'C:\pestertest\SQLPackage.exe' -MSBuildExePath 'C:\pestertest\MSBuild.exe' -erroraction stop + + # Assert + $results = Import-Clixml "$TestDrive\PesterTest.xml" + $results.SQLPackageExe | Should be 'C:\pestertest\SQLPackage.exe' + $results.MSBuildExe | Should be 'C:\pestertest\MSBuild.exe' + $results.version | Should be "$currentversion" + + Assert-MockCalled Export-Clixml -Exactly 1 -Scope It + Assert-MockCalled Test-Path -Exactly 3 -Scope It + } + + It "Saves without throwing"{ + # Act + { + Save-MSSQLCICDHelperConfiguration -SQLPackageExePath 'C:\pestertest\SQLPackage.exe' -MSBuildExePath 'C:\pestertest\MSBuild.exe' -erroraction stop + } | Should not throw + + Assert-MockCalled Export-Clixml -Exactly 1 -Scope It + Assert-MockCalled Test-Path -Exactly 3 -Scope It + + } + # prepare fail + Mock Test-Path {$false} + + It "Throws when Test-Path fails"{ + # Act + { + Save-MSSQLCICDHelperConfiguration -SQLPackageExePath 'C:\pestertest\SQLPackage.exe' -MSBuildExePath 'C:\pestertest\MSBuild.exe' -erroraction stop + } | Should throw + + Assert-MockCalled Test-Path -Exactly 1 -Scope It + + } + } + + Describe "ImportConfig" -Tags Build { + # Prepare + + Mock currentversion {'V1.0.0'} + + $FilePath = "$TestDrive\PesterTest.xml" + $ImportCLIXML = Get-Command Import-Clixml + $buildpath = 'C:\pestertest\MSBuild.exe' + $sqlpath = 'C:\pestertest\SQLPackage.exe' + $currentversion = currentversion + + $export = @{ + MSBuildExe = $buildpath + SQLPackageExe = $sqlpath + Version = currentversion + } + + $export | Export-Clixml -path $FilePath + + Mock Test-Path {$true} + + Mock Import-Clixml -Verifiable { + & $ImportCLIXML $FilePath + } + + It "imports the config with the correct values"{ + # Assert + $results = ImportConfig + $results.SQLPackageExe | Should BeExactly $sqlpath + $results.MSBuildExe | Should BeExactly $buildpath + $results.version | Should BeExactly $currentversion + + Assert-MockCalled currentversion -Exactly 1 -Scope It + Assert-MockCalled Import-Clixml -Exactly 1 -Scope It + Assert-MockCalled Test-Path -Exactly 1 -Scope It + } + + It "imports the config w/o throwing an error"{ + + { + ImportConfig -erroraction stop + } | Should not throw + + Assert-MockCalled currentversion -Exactly 1 -Scope It + Assert-MockCalled Import-Clixml -Exactly 1 -Scope It + Assert-MockCalled Test-Path -Exactly 1 -Scope It + } + + # prepare fail + Mock Test-Path {$false} + + It "Throws an error when path cannot be tested"{ + + { + ImportConfig -erroraction stop + } | Should throw + + Assert-MockCalled currentversion -Exactly 1 -Scope It + Assert-MockCalled Test-Path -Exactly 1 -Scope It + } + + } + + Describe "Get-MSSQLCICDHelperConfiguration" -Tags Build { + # Prepare + Mock currentversion {'V1.0.0'} + + $FilePath = "$TestDrive\PesterTest.xml" + $ImportCLIXML = Get-Command Import-Clixml + $buildpath = 'C:\pestertest\MSBuild.exe' + $sqlpath = 'C:\pestertest\SQLPackage.exe' + $currentversion = currentversion + + $export = @{ + MSBuildExe = $buildpath + SQLPackageExe = $sqlpath + Version = currentversion + } + + $export | Export-Clixml -path $FilePath + + $mockresult = Import-Clixml $FilePath + + Mock Test-Path {$true} + + Mock ImportConfig {$mockresult} + + + + It "Imports the configuration with expected values"{ + # Assert + $results = Get-MSSQLCICDHelperConfiguration $FilePath + $results.SQLPackageExe | Should BeExactly $sqlpath + $results.MSBuildExe | Should BeExactly $buildpath + $results.version | Should BeExactly $currentversion + + Assert-MockCalled importconfig -Exactly 1 -Scope It + } + + It "imports the config w/o throwing an error"{ + + { + Get-MSSQLCICDHelperConfiguration -erroraction stop + } | Should not throw + + Assert-MockCalled importconfig -Exactly 1 -Scope It + } + + # prepare fail + Mock importconfig {throw "Could not import config. Make sure it exists or save a new config."} + + It "Throws an error when nested function fails"{ + + { + Get-MSSQLCICDHelperConfiguration -erroraction stop + } | Should throw "Could not import config. Make sure it exists or save a new config." + + Assert-MockCalled importconfig -Exactly 1 -Scope It + } + + } + + Describe "Get-MSSQLCICDHelperPaths" -Tags Build { + + #create 1 MSBuild.exe and 2 SQLPackage.exe 1 non existing file. + + New-Item -Path $TestDrive -Name ExePath1 -ItemType Directory + New-Item -Path $TestDrive -Name ExePath2 -ItemType Directory + New-Item -Path $TestDrive -Name EmptyFolder -ItemType Directory + + New-Item -Path $TestDrive\ExePath1\MSBuild.exe -ItemType File + New-Item -Path $TestDrive\ExePath1\SQLPackage.exe -ItemType File + New-Item -Path $TestDrive\ExePath2\SQLPackage.exe -ItemType File + New-Item -Path $TestDrive\ExePath1\Itshouldignorethis.exe -ItemType File + + Context "Mandatory Parameters" { + It "Parameter Typetofind should be mandatory"{ + + (Get-Command "Get-MSSQLCICDHelperPaths").Parameters['Typetofind'].Attributes.Mandatory | Should Be $true + + } + + It "Parameter Rootpath should be mandatory"{ + + (Get-Command "Get-MSSQLCICDHelperPaths").Parameters['Rootpath'].Attributes.Mandatory | Should Be $true + + } + + It "Should throw an error when no valid typetofind was entered" { + { + Get-MSSQLCICDHelperPaths -typetofind Pester -rootpath $TestDrive -erroraction stop + } | Should Throw + + } + + It "Should throw an error when no valid rootpath was entered for MSBuild"{ + { + Get-MSSQLCICDHelperPaths -typetofind MSBuild -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + + } + + It "Should throw an error when no valid rootpath was entered for SQLPackage"{ + { + Get-MSSQLCICDHelperPaths -typetofind SQLPackage -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + + } + } + + Context "No Files Found"{ + It "Should throw an error when no files were found for MSBuild"{ + { + Get-MSSQLCICDHelperPaths -typetofind MSBuild -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + + } + + It "Should throw an error when no files were found for SQLPackage"{ + { + Get-MSSQLCICDHelperPaths -typetofind SQLPackage -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + + } + } + + Context "File counts"{ + + It "Should find one MSBuild.exe when searching MSBuild"{ + + (Get-MSSQLCICDHelperPaths -typetofind MSBuild -rootpath $TestDrive).count | Should BeExactly 1 + + } + + It "Should find two SQLPackage.exe when searching SQLPackage"{ + + (Get-MSSQLCICDHelperPaths -typetofind SQLPackage -rootpath $TestDrive).count | Should BeExactly 2 + + } + + It "Should find three total *.exe when searching Both"{ + + (Get-MSSQLCICDHelperPaths -typetofind Both -rootpath $TestDrive).count | Should BeExactly 3 + + } + } + + Context "Correct file paths"{ + It "Should find find the correct path to MSbuild.exe"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind MSBuild -rootpath $TestDrive + + $results | Should contain "$TestDrive\exepath1\MSBuild.exe" + + } + + It "Should find find the correct paths to SQLPackage.exe"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind SQLPackage -rootpath $TestDrive + + $results | Should contain "$TestDrive\exepath1\SQLPackage.exe" + $results | Should contain "$TestDrive\exepath2\SQLPackage.exe" + + } + + It "Should find find the correct paths to Both *.exe"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind Both -rootpath $TestDrive + + $results | Should contain "$TestDrive\exepath1\MSBuild.exe" + $results | Should contain "$TestDrive\exepath1\SQLPackage.exe" + $results | Should contain "$TestDrive\exepath2\SQLPackage.exe" + + } + + It "Should not contain SQLPackage elements when looking for MSBuild"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind MSBuild -rootpath $TestDrive + + $results | Should not contain "$TestDrive\exepath1\SQLPackage.exe" + $results | Should not contain "$TestDrive\exepath2\SQLPackage.exe" + + } + + It "Should not contain MSBuild elements when looking for SQLPackage"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind SQLPackage -rootpath $TestDrive + + $results | Should not contain "$TestDrive\exepath1\MSBuild.exe" + + } + + It "Should never contain the dummy file when running MSBuild"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind MSBuild -rootpath $TestDrive + + $results | Should Not contain "$TestDrive\ExePath1\Itshouldignorethis.exe" + + } + + It "Should never contain the dummy file when running SQLPackage"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind SQLPackage -rootpath $TestDrive + + $results | Should Not contain "$TestDrive\ExePath1\Itshouldignorethis.exe" + + } + + It "Should never contain the dummy file when running Both"{ + + $results = Get-MSSQLCICDHelperPaths -typetofind Both -rootpath $TestDrive + + $results | Should Not contain "$TestDrive\ExePath1\Itshouldignorethis.exe" + + } + } + + + Context "Throws" { + It "Should not Throw when searching MSBuild"{ + + {Get-MSSQLCICDHelperPaths -typetofind MSBuild -rootpath $TestDrive } | Should Not Throw + + } + + It "Should not Throw when searching SQLPackage"{ + + {Get-MSSQLCICDHelperPaths -typetofind SQLPackage -rootpath $TestDrive } | Should Not Throw + + } + + It "Should not Throw when searching Both"{ + + {Get-MSSQLCICDHelperPaths -typetofind Both -rootpath $TestDrive } | Should Not Throw + + } + } + + + + } + + Describe "Get-MSSQLCICDHelperFiletoBuildDeploy" -Tags Build { + + #create 1 of each type, dummyfile, a dir with multiple of the same and an empty dir + # folders + New-Item -Path $TestDrive -Name Single -ItemType Directory + New-Item -Path $TestDrive -Name Multiple -ItemType Directory + New-Item -Path $TestDrive -Name Empty -ItemType Directory + + # Singles + New-Item -Path $TestDrive\Single\Solution.sln -ItemType File + New-Item -Path $TestDrive\Single\SQLProject.sqlproj -ItemType File + New-Item -Path $TestDrive\Single\DBToDeploy.dacpac -ItemType File + New-Item -Path $TestDrive\Single\DBToDeploy.publish.xml -ItemType File + New-Item -Path $TestDrive\Single\SSISPackages.dtspac -ItemType File + + #To Ignore Singles + New-Item -Path $TestDrive\Single\DBToIgnore.nonpublish.xml -ItemType File + New-Item -Path $TestDrive\Single\Itshouldignorethis.exe -ItemType File + + # Multiple + + New-Item -Path $TestDrive\Multiple\Solution1.sln -ItemType File + New-Item -Path $TestDrive\Multiple\SQLProject1.sqlproj -ItemType File + New-Item -Path $TestDrive\Multiple\DBToDeploy1.dacpac -ItemType File + New-Item -Path $TestDrive\Multiple\DBToDeploy1.publish.xml -ItemType File + New-Item -Path $TestDrive\Multiple\SSISPackages1.dtspac -ItemType File + + $date = (Get-Date).AddDays(-1-$i) + + Set-ItemProperty -Path $TestDrive\Multiple\Solution1.sln -Name LastWriteTime -Value $date + Set-ItemProperty -Path $TestDrive\Multiple\SQLProject1.sqlproj -Name LastWriteTime -Value $date + Set-ItemProperty -Path $TestDrive\Multiple\DBToDeploy1.dacpac -Name LastWriteTime -Value $date + Set-ItemProperty -Path $TestDrive\Multiple\DBToDeploy1.publish.xml -Name LastWriteTime -Value $date + Set-ItemProperty -Path $TestDrive\Multiple\SSISPackages1.dtspac -Name LastWriteTime -Value $date + + New-Item -Path $TestDrive\Multiple\Solution2.sln -ItemType File + New-Item -Path $TestDrive\Multiple\SQLProject2.sqlproj -ItemType File + New-Item -Path $TestDrive\Multiple\DBToDeploy2.dacpac -ItemType File + New-Item -Path $TestDrive\Multiple\DBToDeploy2.publish.xml -ItemType File + New-Item -Path $TestDrive\Multiple\SSISPackages2.dtspac -ItemType File + + #To Ignore Multiple + New-Item -Path $TestDrive\Multiple\DBToIgnore.nonpublish.xml -ItemType File + New-Item -Path $TestDrive\Multiple\Itshouldignorethis.exe -ItemType File + + Context "Mandatory Paramaters"{ + + It "Parameter Typetofind should be mandatory"{ + + (Get-Command "Get-MSSQLCICDHelperFiletoBuildDeploy").Parameters['Typetofind'].Attributes.Mandatory | Should Be $true + + } + + It "Parameter Rootpath should be mandatory"{ + + (Get-Command "Get-MSSQLCICDHelperFiletoBuildDeploy").Parameters['Rootpath'].Attributes.Mandatory | Should Be $true + + } + + It "Should throw an error when no valid typetofind was entered"{ + { + Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Pester -rootpath $TestDrive -erroraction stop + } | Should Throw + + } + + It "Should throw an error when a non-existing folder was entered for type Solution"{ + { + Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + } + + It "Should throw an error when a non-existing folder was entered for type project"{ + { + Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Project -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + } + + It "Should throw an error when a non-existing folder was entered for type DacPac"{ + { + Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + } + + It "Should throw an error when a non-existing folder was entered for type PublishProfile"{ + { + Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + } + + It "Should throw an error when a non-existing folder was entered for type DTSPac"{ + { + Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\NonExistingFolder -erroraction stop + } | Should Throw + } + } + + Context "No File Found" { + + It "Should throw an error when no file has been found for type Solution"{ + + { Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\Empty -erroraction stop } | Should Throw + + } + + It "Should throw an error when no file has been found for type project"{ + + { Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind project -rootpath $TestDrive\Empty -erroraction stop } | Should Throw + + } + + It "Should throw an error when no file has been found for type DacPac"{ + + { Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\Empty -erroraction stop } | Should Throw + + } + + It "Should throw an error when no file has been found for type PublishProfile"{ + + { Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\Empty -erroraction stop } | Should Throw + + } + + It "Should throw an error when no file has been found for type DTSPac"{ + + { Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\Empty -erroraction stop } | Should Throw + + } + } + + Context "Folders with Single file" {} + + Context "File Counts" { + #single files Count + It "Should Find a single file for type Solution"{ + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\Single).count | Should BeExactly 1 + + } + + It "Should Find a single file for type project"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind project -rootpath $TestDrive\Single).count | Should BeExactly 1 + + } + + It "Should Find a single file for type DacPac"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\Single).count | Should BeExactly 1 + + } + + It "Should Find a single file for type PublishProfile"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\Single).count | Should BeExactly 1 + + } + + It "Should Find a single file for type DTSPac"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\Single).count | Should BeExactly 1 + + } + } + Context "Correct File Paths" { + #file matches + It "Single Filename match for type Solution"{ + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\Single + + $results.Fullname | Should contain "$TestDrive\Single\Solution.sln" + + } + + It "Single Filename match for type project"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Project -rootpath $TestDrive\Single + + $results.Fullname | Should contain "$TestDrive\Single\SQLProject.sqlproj" + + } + + It "Single Filename match for type DacPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\Single + + $results.Fullname | Should contain "$TestDrive\Single\DBToDeploy.dacpac" + + } + + It "Single Filename match for type PublishProfile"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\Single + + $results.Fullname | Should contain "$TestDrive\Single\DBToDeploy.publish.xml" + + } + + It "Single Filename match for type DTSPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\Single + + $results.Fullname | Should contain "$TestDrive\Single\SSISPackages.dtspac" + + } + } + Context "Dummy Files" { + + #file matches + It "Dummy Exclude Single for type Solution"{ + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\Single + + $results.Fullname | Should not contain "$TestDrive\Single\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Single\Itshouldignorethis.exe" + + } + + It "Dummy Exclude Single for type project"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Project -rootpath $TestDrive\Single + + $results.Fullname | Should not contain "$TestDrive\Single\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Single\Itshouldignorethis.exe" + + } + + It "Dummy Exclude Single for type DacPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\Single + + $results.Fullname | Should not contain "$TestDrive\Single\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Single\Itshouldignorethis.exe" + + } + + It "Dummy Exclude Single for type PublishProfile"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\Single + + $results.Fullname | Should not contain "$TestDrive\Single\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Single\Itshouldignorethis.exe" + + } + + It "Dummy Exclude Single for type DTSPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\Single + + $results.Fullname | Should not contain "$TestDrive\Single\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Single\Itshouldignorethis.exe" + + + + } + + } + + Context "Folders with Multiple files" {} + + Context "File Counts" { + #single files Count + It "Should Find a single file in folder with Multiple files for type Solution"{ + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\Multiple).count | Should BeExactly 1 + + } + + It "Should Find a single file in folder with Multiple files for type project"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind project -rootpath $TestDrive\Multiple).count | Should BeExactly 1 + + } + + It "Should Find a single file in folder with Multiple files for type DacPac"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\Multiple).count | Should BeExactly 1 + + } + + It "Should Find a single file in folder with Multiple files for type PublishProfile"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\Multiple).count | Should BeExactly 1 + + } + + It "Should Find a single file in folder with Multiple files for type DTSPac"{ + + + (Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\Multiple).count | Should BeExactly 1 + + } + } + Context "Correct File Paths" { + #file matches + It "Multiple Filename match for type Solution"{ + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\Multiple + + $results.Fullname | Should contain "$TestDrive\Multiple\Solution2.sln" + + } + + It "Multiple Filename match for type project"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Project -rootpath $TestDrive\Multiple + + $results.Fullname | Should contain "$TestDrive\Multiple\SQLProject2.sqlproj" + + } + + It "Multiple Filename match for type DacPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\Multiple + + $results.Fullname | Should contain "$TestDrive\Multiple\DBToDeploy2.dacpac" + + } + + It "Multiple Filename match for type PublishProfile"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\Multiple + + $results.Fullname | Should contain "$TestDrive\Multiple\DBToDeploy2.publish.xml" + + } + + It "Multiple Filename match for type DTSPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\Multiple + + $results.Fullname | Should contain "$TestDrive\Multiple\SSISPackages2.dtspac" + + } + } + Context "Dummy Files" { + + #file matches + It "Multiple Dummy Exclude Single for type Solution"{ + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Solution -rootpath $TestDrive\Multiple + + $results.Fullname | Should not contain "$TestDrive\Multiple\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Multiple\Itshouldignorethis.exe" + + } + + It "Multiple Dummy Exclude Single for type project"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind Project -rootpath $TestDrive\Multiple + + $results.Fullname | Should not contain "$TestDrive\Multiple\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Multiple\Itshouldignorethis.exe" + + } + + It "Multiple Dummy Exclude Single for type DacPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DacPac -rootpath $TestDrive\Multiple + + $results.Fullname | Should not contain "$TestDrive\Multiple\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Multiple\Itshouldignorethis.exe" + + } + + It "Multiple Dummy Exclude Single for type PublishProfile"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind PublishProfile -rootpath $TestDrive\Multiple + + $results.Fullname | Should not contain "$TestDrive\Multiple\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Multiple\Itshouldignorethis.exe" + + } + + It "Multiple Dummy Exclude Single for type DTSPac"{ + + + $results = Get-MSSQLCICDHelperFiletoBuildDeploy -typetofind DTSPac -rootpath $TestDrive\Multiple + + $results.Fullname | Should not contain "$TestDrive\Multiple\DBToIgnore.nonpublish.xml" + $results.Fullname | Should not contain "$TestDrive\Multiple\Itshouldignorethis.exe" + + + + } + + } + + } + Describe "Invoke-Cmd" -Tags Build { + + #New-Item -Path $TestDrive\poutput.log -ItemType File + #New-Item -Path $TestDrive\errorpoutput.log -ItemType File + + $executable = 'powershell.exe' + $passingarguments = 'Write-Output ''Test sentence for assertion''' + $passingAssertion = 'Test sentence for assertion' + $failingarguments = 'throw' + $FailingAssertion = '' + $logfile = "$TestDrive\poutput.log" + $errorlogfile = "$TestDrive\errorpoutput.log" + + It "Mandatory Parameters"{ + (Get-Command "Invoke-Cmd").Parameters['Executable'].Attributes.Mandatory | Should Be $true + (Get-Command "Invoke-Cmd").Parameters['Arguments'].Attributes.Mandatory | Should Be $true + (Get-Command "Invoke-Cmd").Parameters['Logfile'].Attributes.Mandatory | Should Be $true + (Get-Command "Invoke-Cmd").Parameters['errorlogfile'].Attributes.Mandatory | Should Be $true + } + + It "Should not throw when all parameters are entered on a successfull command"{ + { Invoke-Cmd -executable $executable -arguments $passingarguments -logfile $logfile -errorlogfile $errorlogfile } | Should not Throw + } + + It "Should throw on an invalid logfile path parent"{ + { Invoke-Cmd -executable $executable -arguments $passingarguments -logfile $testdrive\NonExistingFolder\file.log -errorlogfile $errorlogfile -erroraction stop } | Should Throw + } + + It "Should throw on an invalid errorlogfile path parent"{ + { Invoke-Cmd -executable $executable -arguments $passingarguments -logfile $logfile -errorlogfile $testdrive\NonExistingFolder\file.log -erroraction stop } | Should Throw + } + + It "Should throw when a non existing executable is used"{ + { Invoke-Cmd -executable 'failingassert.error' -arguments $passingarguments -logfile $logfile -errorlogfile $errorlogfile -erroraction stop } | Should Throw + } + + It "Should produce the correct results when calling write-output command"{ + $results = Invoke-Cmd -executable $executable -arguments $passingarguments -logfile $logfile -errorlogfile $errorlogfile + #getting results + $results.ExitCode | Should -BeExactly 0 + $results.ErrorOutput | Should -BeExactly -1 + $results.Output.Trim() | Should -BeExactly $passingAssertion + #test created files + Test-Path -Path $logfile | Should be $true + Test-Path -Path $errorlogfile | Should be $true + + $producedlogfile = Get-Content $logfile + $producederrorlogfile = Get-Content $errorlogfile + + $producedlogfile[0].Trim() | Should -BeExactly $passingAssertion + $producederrorlogfile.Trim() | Should -BeExactly -1 + } + + It "Should produce the correct results when calling throw command"{ + $results = Invoke-Cmd -executable $executable -arguments $failingarguments -logfile $logfile -errorlogfile $errorlogfile + + $results.ExitCode | Should -BeExactly 1 + $results.ErrorOutput | Should -BeExactly 83 + $results.Output | Should -BeExactly $FailingAssertion + + Test-Path -Path $logfile | Should be $true + Test-Path -Path $errorlogfile | Should be $true + + $producedlogfile = Get-Content $logfile + $producederrorlogfile = Get-Content $errorlogfile + + $producedlogfile | Should -BeExactly $FailingAssertion + $producederrorlogfile.Trim() | Should -BeExactly 83 + } + } + + Describe "Invoke-MSSQLCICDHelperMSBuild" -Tags Build { + Context "Errors & Dependencies" { + #Context "test nested context"{} + ############################ + + ############################ + mock Get-Module {$false} + + It "Should throw when Invoke-MSBuild is not Available"{ + {Invoke-MSSQLCICDHelperMSBuild -UseInvokeMSBuildModule -erroraction stop} | Should throw + + Assert-MockCalled Get-Module -Exactly 1 -Scope It + } + + New-Item -Path $TestDrive -Name Solution -ItemType Directory + New-Item -Path $TestDrive -Name Empty -ItemType Directory + + New-Item -Path $TestDrive\MSBuild.exe -ItemType File + New-Item -Path $TestDrive\SQLPackage.exe -ItemType File + + New-Item -Path $TestDrive\Solution\Solution.sln -ItemType File + + $filetobuild = "$TestDrive\Solution\Solution.sln" + + Mock currentversion {'V1.0.0'} + + $configpath = "$TestDrive\PesterTest.xml" + #$ImportCLIXML = Get-Command Import-Clixml + $buildpath = "$Testdrive\MSBuild.exe" + $sqlpath = "$testdrive\SQLPackage.exe" + $currentversion = currentversion + + $export = @{ + MSBuildExe = $buildpath + SQLPackageExe = $sqlpath + Version = $currentversion + } + + $export | Export-Clixml -path $configpath + + $mockresult = Import-Clixml $configpath + + Mock ImportConfig {$mockresult} + + it "Should throw an error on an empty path" { + {Invoke-MSSQLCICDHelperMSBuild -filename $testRoot\NonExisting.sln -erroraction stop} | Should throw + + Assert-MockCalled importconfig -Exactly 0 -Scope It + } + + mock Get-MSSQLCICDHelperFiletoBuildDeploy {throw} + #mock Get-ChildItem {} + mock Invoke-Expression {throw} + + # it "Should throw when an exception occurs with manual filename " { + + # {Invoke-MSSQLCICDHelperMSBuild -filename $filetobuild -erroraction stop} | Should throw + # } + + it "Should throw when an exception occurs with Autodiscovery filename" { + + {Invoke-MSSQLCICDHelperMSBuild -erroraction stop} | Should throw + + Assert-MockCalled importconfig -Exactly 1 -Scope It + Assert-MockCalled Get-MSSQLCICDHelperFiletoBuildDeploy -Exactly 1 -Scope It + } + } + } + + Describe "Invoke-MSSQLCICDHelperSQLPackage" -Tags Build { + + } + +} + + diff --git a/build.ps1 b/build.ps1 index a9be7cd..66b4a5a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -11,7 +11,7 @@ param ($Task = 'Default') # Grab nuget bits, install modules, set build variables, start build. " Install Dependent Modules" Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null -Install-Module InvokeBuild, BuildHelpers, PSScriptAnalyzer, PlatyPS -force -Scope CurrentUser #PSDeploy, +Install-Module InvokeBuild, BuildHelpers, PSDeploy, PSScriptAnalyzer, PlatyPS -force -Scope CurrentUser #PSDeploy, Install-Module Pester -Force -SkipPublisherCheck -Scope CurrentUser " Import Dependent Modules" diff --git a/localpester.ps1 b/localpester.ps1 new file mode 100644 index 0000000..02cc113 --- /dev/null +++ b/localpester.ps1 @@ -0,0 +1,45 @@ +<# +.Description +Installs and loads all the required modules for the build. +Derived from scripts written by Warren F. (RamblingCookieMonster) +#> + +[cmdletbinding()] +param ($Task = 'LocalPester') +"Starting build" +# " Installing latest NuGet Provider" +#Install-PackageProvider -name NuGet -Force +# Grab nuget bits, install modules, set build variables, start build. +" Install Dependent Modules" +Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null +Install-Module InvokeBuild, BuildHelpers, PSDeploy, PlatyPS -force -Scope CurrentUser +Install-Module PSScriptAnalyzer, Pester -Force -SkipPublisherCheck -Scope CurrentUser + +" Import Dependent Modules" +$modules = New-Object System.Collections.ArrayList +$modules.add('InvokeBuild') +$modules.add('BuildHelpers') +$modules.add('PSScriptAnalyzer') + +foreach($module in $modules) { + if(Get-Module $$module -ErrorAction 'Ignore' -ListAvailable){ + "Module $module is installed. skipping install" + }else{ + "Installing $module ..." + Import-Module $module + } + +} + +Set-BuildEnvironment + +" InvokeBuild" +Invoke-Build $Task -Result result -Verbose +if ($Result.Error) +{ + exit 1 +} +else +{ + exit 0 +} \ No newline at end of file