From f046d22ef8373cfdbc27f5b7fe85c8a686a349d9 Mon Sep 17 00:00:00 2001 From: Peter Bajurny Date: Thu, 31 Mar 2022 12:40:05 -0500 Subject: [PATCH] Autogeneration improvements progress on #369 --- build.ps1 | 2 +- ci/Invoke-BatchUpdateFunctionGeneration.ps1 | 102 +++++++++++++++++++- ci/Invoke-HelperFunctionGeneration.ps1 | 79 +++++++++++---- psake.ps1 | 27 ++++-- 4 files changed, 177 insertions(+), 33 deletions(-) diff --git a/build.ps1 b/build.ps1 index 2bc76320..fc6e9ff5 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,7 +1,7 @@ [cmdletbinding()] param( [parameter( Position = 0)] - [ValidateSet('Init','Clean','Update','Compile','Import','Test','Full','Deploy','Skip','Docs')] + [ValidateSet('Init','Clean','Nuget','Generate','GenerateOnly','Compile','Import','Test','Full','Deploy','Skip','Docs')] [string[]] $Task = @('Compile','Import'), [parameter()] diff --git a/ci/Invoke-BatchUpdateFunctionGeneration.ps1 b/ci/Invoke-BatchUpdateFunctionGeneration.ps1 index 83f9e9d7..8c6dd700 100644 --- a/ci/Invoke-BatchUpdateFunctionGeneration.ps1 +++ b/ci/Invoke-BatchUpdateFunctionGeneration.ps1 @@ -15,20 +15,108 @@ function Invoke-BatchUpdateFunctionGeneration { $subType = New-Object $fullType $paramBlock = @() $paramHelpBlock = @() + $listOrDictParamBlock = @() $exampleParamString = "" $subType | Get-Member -MemberType Property | Where-Object {$_.Name -ne 'ETag'} | ForEach-Object { $paramName = $_.Name $paramType = $_.Definition.Split(' ',2)[0] - $paramBlock += " [parameter()]`n [$paramType]`n `$$paramName," + if ($paramType -match '\[.*\]') { + $typeSplit = ($paramType | Select-String -Pattern '([\w|\.]+)\[(.*)\]' -AllMatches).Matches.Groups[1..2].Value + if ($typeSplit[0] -match 'IList') { + $isList = $true + $isDict = $false + $dictKey = $null + $paramType = $typeSplit[1] + } + elseif ($typeSplit[0] -match 'IDictionary') { + $isDict = $true + $isList = $false + $dictKey, $paramType = $typeSplit[1].Split(',') + } + else { + # So far the only types that triger this are Nullable values + # System.Nullable[int] + # System.Nullable[float] + # System.Nullable[bool] + # System.Nullable[double] + # System.Nullable[long] + $isList = $false + $isDict = $false + $dictKey = $null + $paramType = $paramType + } + } + else { + $isList = $false + $isDict = $false + $dictKey = $null + $paramType = $paramType + } + if ($paramType -eq 'bool') { + $paramType = 'switch' + } + $paramBlockType = if ($isList) { + "$paramType[]" + } + elseif ($isDict) { + 'System.Collections.Hashtable' + } + else { + $paramType + } + $paramBlock += " [parameter()]`n [$paramBlockType]`n `$$paramName," if ($paramType -match '^Google\.') { - $helperFunctionName = "Add-GS" + $TargetApi + $paramType.Split('.')[-1] - $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n`n To create this type, use the function $helperFunctionName or instantiate the type directly via New-Object '$paramType'.`n" + $helperFunctionName = "Add-GS" + $TargetApi + $(if ($paramType -match '\.'){$paramType.Split('.')[-1]}else{$paramType}) + if ($isList) { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramBlockType].`n`n To create this type, use the function $helperFunctionName or instantiate the type directly via New-Object '$paramType'.`n" + } + elseif ($isDict) { + $dictHelpBlock = ".PARAMETER $paramName`n Accepts the following type: [$paramBlockType]." + $dictHelpBlock += "`n The key(s) of the Hashtable should be a [$dictKey] and the value(s) should be a [$paramType]" + $dictHelpBlock += "`n`n To create an object of type [$paramType], use the function $helperFunctionName or instantiate the type directly via New-Object '$paramType'.`n" + $paramHelpBlock += $dictHelpBlock + } + else { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramBlockType].`n`n To create this type, use the function $helperFunctionName or instantiate the type directly via New-Object '$paramBlockType'.`n" + } Invoke-HelperFunctionGeneration -BaseType $paramType } else { - $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n" + if ($isList) { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramBlockType].`n" + } + elseif ($isDict) { + $dictHelpBlock = ".PARAMETER $paramName`n Accepts the following type: [$paramBlockType]." + $dictHelpBlock += "`n The key(s) of the Hashtable should be a [$dictKey] and the value(s) should be a [$paramType]`n" + $paramHelpBlock += $dictHelpBlock + } + else { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramBlockType].`n" + } } $exampleParamString += " -$paramName `$$($paramName.Substring(0,1).ToLower())$($paramName.Substring(1))" + if ($isList) { + $listOrDictParamBlock += @" + $paramName { + `$list = New-Object 'System.Collections.Generic.List[$paramType]' + foreach (`$item in `$$paramName) { + `$list.Add(`$item) + } + `$newRequest.$paramName = `$list + } +"@ + } + if ($isDict) { + $listOrDictParamBlock += @" + $paramName { + `$dict = New-Object 'System.Collections.Generic.Dictionary[[$dictKey],[$paramType]]' + foreach (`$item in `$$paramName.GetEnumerator()) { + `$dict.Add(`$item.Key,`$item.Value) + } + `$newRequest.$paramName = `$dict + } +"@ + } } $paramHelpBlock += ".PARAMETER Requests`n Enables pipeline input of other requests of the same type.`n" $fnValue = @" @@ -63,7 +151,11 @@ $($paramBlock -join "`n") End { `$newRequest = New-Object '$fullType' foreach (`$prop in `$PSBoundParameters.Keys | Where-Object {`$newRequest.PSObject.Properties.Name -contains `$_}) { - `$newRequest.`$prop = `$PSBoundParameters[`$prop] + switch (`$prop) {$(if($listOrDictParamBlock.Count){"`n" + ($listOrDictParamBlock -join "`n")}) + default { + `$newRequest.`$prop = `$PSBoundParameters[`$prop] + } + } } try { New-Object '$BaseType' -Property @{ diff --git a/ci/Invoke-HelperFunctionGeneration.ps1 b/ci/Invoke-HelperFunctionGeneration.ps1 index 39c19713..7ef0ec02 100644 --- a/ci/Invoke-HelperFunctionGeneration.ps1 +++ b/ci/Invoke-HelperFunctionGeneration.ps1 @@ -3,7 +3,7 @@ function Invoke-HelperFunctionGeneration { Param ( [parameter(Mandatory = $true,Position = 0)] [String] - $BaseType = 'Google.Apis.Sheets.v4.Data.BandedRange' + $BaseType ) $TargetApi = $BaseType.Split('.')[2].TrimEnd('s') $OutputPath = [System.IO.Path]::Combine($PSScriptRoot,'..','PSGSuite','Public','Helpers','CIGenerated') @@ -24,17 +24,32 @@ function Invoke-HelperFunctionGeneration { $typeSplit = ($fullType | Select-String -Pattern '([\w|\.]+)\[(.*)\]' -AllMatches).Matches.Groups[1..2].Value if ($typeSplit[0] -match 'IList') { $isList = $true + $isDict = $false + $dictKey = $null $fullType = $typeSplit[1] } elseif ($typeSplit[0] -match 'IDictionary') { $isDict = $true - $fullType = $typeSplit[1].Split(',')[1] + $isList = $false + $dictKey, $fullType = $typeSplit[1].Split(',') + } + else { + # So far the only types that triger this are Nullable values + # System.Nullable[int] + # System.Nullable[float] + # System.Nullable[bool] + # System.Nullable[double] + # System.Nullable[long] + $isList = $false + $isDict = $false + $dictKey = $null + $fullType = $fullType } - # $isList = $typeSplit[0] -match 'IList' - # $fullType = $typeSplit[1] } else { - $isList = $fullType -match 'IList' + $isList = $false + $isDict = $false + $dictKey = $null $fullType = $fullType } if ($fullType -eq 'bool') { @@ -49,14 +64,34 @@ function Invoke-HelperFunctionGeneration { else { $fullType } - $paramName = $_.Name $paramBlock += " [parameter(ParameterSetName = `"Fields`")]`n [$paramType]`n `$$paramName," - if ($paramType -match '^Google\.') { + if ($fullType -match '^Google\.') { $helperFunctionName = "Add-GS" + $TargetApi + $(if ($fullType -match '\.'){$fullType.Split('.')[-1]}else{$fullType}) - $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n`n To create this type, use the function $helperFunctionName or instantiate the type directly via New-Object '$fullType'.`n" + if ($isList) { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n`n To create this type, use the function $helperFunctionName or instantiate the type directly via New-Object '$fullType'.`n" + } + elseif ($isDict) { + $dictHelpBlock = ".PARAMETER $paramName`n Accepts the following type: [$paramType]." + $dictHelpBlock += "`n The key(s) of the Hashtable should be a [$dictKey] and the value(s) should be a [$fullType]" + $dictHelpBlock += "`n`n To create an object of type [$fullType], use the function $helperFunctionName or instantiate the type directly via New-Object '$fullType'.`n" + $paramHelpBlock += $dictHelpBlock + } + else { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n`n To create this type, use the function $helperFunctionName or instantiate the type directly via New-Object '$fullType'.`n" + } } else { - $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n" + if ($isList) { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n" + } + elseif ($isDict) { + $dictHelpBlock = ".PARAMETER $paramName`n Accepts the following type: [$paramType]." + $dictHelpBlock += "`n The key(s) of the Hashtable should be a [$dictKey] and the value(s) should be a [$fullType]`n" + $paramHelpBlock += $dictHelpBlock + } + else { + $paramHelpBlock += ".PARAMETER $paramName`n Accepts the following type: [$paramType].`n" + } } $exampleParamString += " -$paramName `$$($paramName.Substring(0,1).ToLower())$($paramName.Substring(1))" if ($isList) { @@ -167,23 +202,29 @@ $($paramBlock -join "`n") $fullType = $_.Definition.Split(' ',2)[0] if ($fullType -match '\[.*\]') { $typeSplit = ($fullType | Select-String -Pattern '([\w|\.]+)\[(.*)\]' -AllMatches).Matches.Groups[1..2].Value - $isList = $typeSplit[0] -match 'IList' - $fullType = $typeSplit[1] + if ($typeSplit[0] -match 'IList') { + $fullType = $typeSplit[1] + } + elseif ($typeSplit[0] -match 'IDictionary') { + $fullType = $typeSplit[1].Split(',')[1] + } + else { + # So far the only types that triger this are Nullable values + # System.Nullable[int] + # System.Nullable[float] + # System.Nullable[bool] + # System.Nullable[double] + # System.Nullable[long] + $fullType = $fullType + } } else { - $isList = $fullType -match 'IList' $fullType = $fullType } if ($fullType -eq 'bool') { $fullType = 'switch' } - $paramType = if ($isList) { - "$fullType[]" - } - else { - $fullType - } - if ($paramType -match '^Google\.') { + if ($fullType -match '^Google\.') { Invoke-HelperFunctionGeneration -BaseType $fullType } } diff --git a/psake.ps1 b/psake.ps1 index 99ba46e8..eae27bd3 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -57,7 +57,13 @@ task Init { } } -description 'Initialize build environment' -task Clean -depends Init { +task CleanGenerated -depends Init { + $ciGeneratedPath = [System.IO.Path]::Combine($PSScriptRoot,'PSGSuite','Public','Helpers','CIGenerated') + Get-ChildItem $ciGeneratedPath -Filter "*.ps1" -Recurse | Remove-Item -Force -Confirm:$false + " Cleaned CI Generated directory [$ciGeneratedPath]" +} -description 'Cleans CI Generated functions' + +task CleanOutput -depends Init { $zipPath = [System.IO.Path]::Combine($PSScriptRoot,"$($env:BHProjectName).zip") if (Test-Path $zipPath) { Remove-Item $zipPath -Force @@ -84,11 +90,12 @@ task Clean -depends Init { New-Item -Path $outputDir -ItemType Directory | Out-Null } " Cleaned previous output directory [$outputDir]" - $ciGeneratedPath = [System.IO.Path]::Combine($PSScriptRoot,'PSGSuite','Public','Helpers','CIGenerated') - Get-ChildItem $ciGeneratedPath -Filter "*.ps1" -Recurse | Remove-Item -Force -Confirm:$false - " Cleaned CI Generated directory [$ciGeneratedPath]" } -description 'Cleans module output directory' +task Clean -depends CleanGenerated,CleanOutput { + +} -description 'Cleans all build output' + task Nuget -depends Clean { if (-not (Test-Path $outputModVerDir)) { $modDir = New-Item -Path $outputModDir -ItemType Directory -ErrorAction SilentlyContinue @@ -104,7 +111,7 @@ task Nuget -depends Clean { } } -task Update -depends Nuget { +$generateScriptBlock = { Get-ChildItem (Join-Path $PSScriptRoot 'ci') -Recurse -Filter "*.ps1" | ForEach-Object { . $_.FullName } @@ -139,7 +146,11 @@ task Update -depends Nuget { } } -task Compile -depends Update { +task Generate -depends Nuget $generateScriptBlock -description 'Generate BatchUpdate functions' + +task GenerateOnly -depends CleanGenerated $generateScriptBlock -description 'Generate BatchUpdate functions [requires you to run Nuget task to download libraries]' + +task Compile -depends Generate { # Create module output directory $functionsToExport = @() $sutLib = [System.IO.Path]::Combine($sut,'lib') @@ -398,12 +409,12 @@ $pesterScriptBlock = { Write-BuildLog "[$($module.Name)] Removing imported module" $imported | Remove-Module } - Import-Module @module + Import-Module @module -Global } catch { Write-BuildLog "[$($module.Name)] Installing missing module" Install-Module @module -Repository PSGallery -Scope CurrentUser -Force - Import-Module @module + Import-Module @module -Global } } Push-Location