<# .SYNOPSIS Builds the Alkami.PowerShell module system .EXAMPLE .\build-solution.ps1 .PARAMETER Configuration The MSBuild build configuration to use. Typically Release or Debug .PARAMETER CleanFirst Should MSBuild clean the project first? .PARAMETER AsBuildServer Run the tests on a developer machine as a build server .PARAMETER WithTests Run tests after the build .PARAMETER WithAnalyzer Run PSScriptAnalyzer on the project .PARAMETER Fast Run with the least options possible .PARAMETER Full Run with the most options possible #> [CmdletBinding()] Param( $Configuration = "Release", [switch]$CleanFirst, [switch]$AsBuildServer, [switch]$WithTests, [switch]$WithAnalyzer, [switch]$Fast, [switch]$Full ) if ($Fast) { $WithTests = $false $WithAnalyzer = $false $Full = $false } if ($Full) { $WithTests = $true $WithAnalyzer = $true } . $PSScriptRoot\.build\Load-Includes.ps1 $AsBuildServer = $AsBuildServer -or (Test-IsTeamCityProcess) Function Get-ProjectsAndDependencies { $projectlist = New-Object PsObject @{ } $projectlist["Carbon"] = New-Object PsObject @{ ProjectId = "Carbon"; ModuleVersion = "2.5.0"; RequiredModules = @(); } $psdList = Get-ChildItem -Path $PSScriptRoot *.psd1 -recurse foreach ($file in $psdList) { $projectId = $file.BaseName $capturePSDasVariable = Import-PowerShellDataFile -Path $file.FullName $requiredModules = @($capturePSDasVariable.RequiredModules) $moduleVersion = $capturePSDasVariable.ModuleVersion $projectlist[$projectId] = New-Object PsObject @{ ProjectId = $projectId; ModuleVersion = $moduleVersion; RequiredModules = $requiredModules } } return $projectlist } Function Get-XmlWriterSettings { $xmlsettings = New-Object System.Xml.XmlWriterSettings $xmlsettings.Indent = $true $xmlsettings.IndentChars = "`t" return $xmlsettings } # We don't run this locally. if ($AsBuildServer) { ## Gather the latest version and required dependencies from all modules. $projectList = (Get-ProjectsAndDependencies) $xmlsettings = (Get-XmlWriterSettings) $nuspeclist = (Get-ChildItem *.nuspec -recurse) foreach ($file in $nuspeclist) { ## If there is no psd1 in this folder, don't change anything if (!(Get-ChildItem -Path $file.Parent.FullName *.psd1 -Recurse)) { Write-Host "No PSD1 found in [$($file.Parent.FullName)]" continue } ## Don't muck with the global object $myProjectList = $projectlist.Clone() $xml = [Xml](Get-Content $file) $projectName = $xml.package.metadata.id if ($null -ne $xml.package.metadata.dependencies) { foreach ($dependency in $xml.package.metadata.dependencies) { ## If the dependency isn't Alkami centric (example: Carbon) then we will just be keeping it if (($null -ne $dependency) -and ($null -ne $dependency.id) -and ($dependency.id -notmatch 'Alkami') -and !($myProjectList.ContainsKey($dependency.id))) { $projectId = $dependency.id $moduleVersion = $dependency.version $myProjectlist[$projectId] = New-Object PsObject -Properties @{ ProjectId = $projectId; ModuleVersion = $moduleVersion; RequiredModules = @() } ## Add this item to the tree $myProjectList[$projectName].RequiredModules += $projectId } } } $myDependencies = $myProjectList[$projectName].RequiredModules | Sort-Object if (!!($xml.GetElementsByTagName("dependencies"))[0]) { ($xml.package.metadata.RemoveChild(($xml.GetElementsByTagName("dependencies"))[0])) | Out-Null } $dependencyList = $xml.CreateElement("dependencies") ## Write out all of the dependencies of this project foreach ($dependencyId in $myDependencies) { $dependency = $myProjectlist[$dependencyId] ## Create required dependencies with the latest version of the module in the current branch if ($dependency) { $node = $xml.CreateElement("dependency") ($node.SetAttribute("id", $dependency.ProjectId)) | Out-Null ($node.SetAttribute("version", $dependency.ModuleVersion)) | Out-Null } if ($null -ne $node) { ($dependencyList.AppendChild($node)) | Out-Null } } ($xml.package.metadata.AppendChild($dependencyList)) | Out-Null $sb = [System.Text.StringBuilder]::new() $writer = [System.Xml.XmlWriter]::Create($sb, $xmlSettings) ## Update the actual XML element with the values in the XmlWriter ($xml.Save($writer)) | Out-Null ## Save the content of the XML file back to disk where we found the original one. (Set-Content -Value $sb.ToString() -Path $file.FullName) | Out-Null } } Function Get-AnalyzerResults { Param( $FolderPath ) process { $failingResults = @() $folderTypes = @('Public','Private') foreach ($folderType in $folderTypes) { if (Test-Path (Join-Path $FolderPath $folderType)) { $testFiles = (Get-ChildItem -Path (Join-Path $FolderPath $folderType) "*.ps1" -recurse) foreach ($file in $testFiles) { Write-Verbose "Analyzing $file" $reportSummary = Invoke-ScriptAnalyzer $file.FullName -Severity Error,Warning if (!!($reportSummary)) { $failingResults += New-Object PSObject -Property @{ Filename = $file.FullName; TestResult = $null; Analyzer = $reportSummary; } } } } } return $failingResults } } $results = @() (Get-ChildItem $PSScriptRoot -Directory) | ForEach-Object { $FolderPath = $_.FullName; & $PSScriptRoot\build-project.ps1 $FolderPath $Configuration -CleanFirst:$CleanFirst -AsBuildServer:$AsBuildServer if ($WithAnalyzer) { $results += Get-AnalyzerResults $FolderPath } } ## TeamCity does something else here ## This is intended to only run if we're in development if ($WithTests) { $results += .\test-solution.ps1 -NoAnalyzer } if ($WithAnalyzer -or $WithTests) { return $results }