utilities/tools/helper/Set-ModuleFileAndFolderSetup.ps1 (139 lines of code) (raw):

<# .SYNOPSIS Idempotently set an initial file and folder structure for an intended module path .DESCRIPTION Idempotently set an initial file and folder structure for an intended module path. Will setup the path if it does not exist yet. Most files will contain an initial set of content. Note: The ReadMe & main.json file(s) will not be generated by this script. .PARAMETER FullModuleFolderPath Mandatory. The full module path to create. .PARAMETER CurrentLevelFolderPath Optional. The level the current invocation is at. Used for recursion. Do not provide. .EXAMPLE Set-ModuleFileAndFolderSetup -FullModuleFolderPath '<repoPath>\avm\res\storage\storage-account\blob-service\container' Results into: - Added file [<repoPath>\avm\res\storage\storage-account\main.bicep] - Added file [<repoPath>\avm\res\storage\storage-account\version.json] - Added file [<repoPath>\avm\res\storage\storage-account\tests\e2e\defaults\main.test.bicep] - Added file [<repoPath>\avm\res\storage\storage-account\tests\e2e\waf-aligned\main.test.bicep] - Added file [<repoPath>\avm\res\storage\storage-account\blob-service\main.bicep] - Added file [<repoPath>\avm\res\storage\storage-account\blob-service\container\main.bicep] .EXAMPLE Set-ModuleFileAndFolderSetup -FullModuleFolderPath '<repoPath>\avm\res\storage\storage-account' Results into: - Added file [<repoPath>\avm\res\storage\storage-account\main.bicep] - Added file [<repoPath>\avm\res\storage\storage-account\version.json] - Added file [<repoPath>\avm\res\storage\storage-account\tests\e2e\defaults\main.test.bicep] - Added file [<repoPath>\avm\res\storage\storage-account\tests\e2e\waf-aligned\main.test.bicep] #> function Set-ModuleFileAndFolderSetup { [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $true)] [string] $FullModuleFolderPath, [Parameter(Mandatory = $false)] [string] $CurrentLevelFolderPath ) if ([String]::IsNullOrEmpty($CurrentLevelFolderPath)) { # Extract path elements $repoRoot, $moduleType, $resourceTypeIdentifier = $FullModuleFolderPath -split '[\/|\\]avm[\/|\\](res|ptn|utl)[\/|\\]' # .*/bicep-registry-modules, res|ptn|utl, <provider>/<resourceType> # Split resource type identifier into components $providerNamespace, $resourceType, $childResourceType = $resourceTypeIdentifier -split '[\/|\\]', 3 # <provider>, <resourceType>, <childResourceType> # Join the required path to get up to the resource type folder $CurrentLevelFolderPath = Join-Path $repoRoot 'avm' $moduleType $providerNamespace $resourceType } # Collect data $resourceTypeIdentifier = ($CurrentLevelFolderPath -split '[\/|\\]avm[\/|\\](res|ptn|utl)[\/|\\]')[2] # avm/res/<provider>/<resourceType> $isTopLevel = ($resourceTypeIdentifier -split '[\/|\\]').Count -eq 2 # Mandatory files # =============== # Template file # ------------- $bicepFilePath = Join-Path $CurrentLevelFolderPath 'main.bicep' if (-not (Test-Path $bicepFilePath)) { if ($PSCmdlet.ShouldProcess("File [$bicepFilePath]", 'Add')) { $null = New-Item -Path $bicepFilePath -ItemType 'File' -Force } $defaultTemplateSourceFilePath = Join-Path $PSScriptRoot 'src' ($isTopLevel ? 'src.main.bicep' : 'src.child.main.bicep') if (Test-Path $defaultTemplateSourceFilePath) { $defaultTemplateSourceFileContent = Get-Content -Path $defaultTemplateSourceFilePath if ($PSCmdlet.ShouldProcess("content for file [$bicepFilePath]", 'Set')) { $null = Set-Content -Path $bicepFilePath -Value $defaultTemplateSourceFileContent } } Write-Verbose "Added file [$bicepFilePath]" -Verbose } # README can be generated by parent script # main.json can be generated by parent script # Top-level-only files # ==================== if ($isTopLevel) { # Version file # ------------ $versionFilePath = Join-Path $CurrentLevelFolderPath 'version.json' if (-not (Test-Path $versionFilePath)) { if ($PSCmdlet.ShouldProcess("File [$versionFilePath]", 'Add')) { $null = New-Item -Path $versionFilePath -ItemType 'File' -Force } $versionSourceFilePath = Join-Path $PSScriptRoot 'src' 'src.version.json' if (Test-Path $versionSourceFilePath) { $versionSourceFileContent = Get-Content -Path $versionSourceFilePath if ($PSCmdlet.ShouldProcess("content for file [$versionFilePath]", 'Set')) { $null = Set-Content -Path $versionFilePath -Value $versionSourceFileContent } } Write-Verbose "Added file [$versionFilePath]" -Verbose } # Defaults test file # ----------------- $testCasesPath = Join-Path $CurrentLevelFolderPath 'tests' 'e2e' if (-not (Test-Path $testCasesPath)) { $null = New-Item -Path $testCasesPath -ItemType 'Directory' -Force } $currentTestFolders = Get-ChildItem -Path $testCasesPath -Directory | ForEach-Object { $_.Name } if (($currentTestFolders -match '.*defaults').count -eq 0) { $defaultTestFilePath = Join-Path $testCasesPath 'defaults' 'main.test.bicep' if ($PSCmdlet.ShouldProcess("file [$defaultTestFilePath]", 'Add')) { $null = New-Item -Path $defaultTestFilePath -ItemType 'File' -Force } $defaultTestTemplateSourceFilePath = Join-Path $PSScriptRoot 'src' 'src.main.test.bicep' if (Test-Path $defaultTestTemplateSourceFilePath) { $defaultTestTemplateSourceFileContent = Get-Content -Path $defaultTestTemplateSourceFilePath $suggestedServiceShort = '{0}def' -f (($resourceTypeIdentifier -split '[\/|\\|-]' | ForEach-Object { $_[0] }) -join '') # e.g., npemin $defaultTestTemplateSourceFileContent = $defaultTestTemplateSourceFileContent -replace '<serviceShort>', $suggestedServiceShort $suggestedResourceGroupName = $resourceTypeIdentifier -replace '[\/|\\]', '.' -replace '-' # e.g., network.privateendpoints $defaultTestTemplateSourceFileContent = $defaultTestTemplateSourceFileContent -replace '<The test resource group name>', $suggestedResourceGroupName if ($PSCmdlet.ShouldProcess("content for file [$defaultTestFilePath]", 'Set')) { $null = Set-Content -Path $defaultTestFilePath -Value $defaultTestTemplateSourceFileContent } } Write-Verbose "Added file [$defaultTestFilePath]" -Verbose } # WAF-aligned test file # --------------------- if (($currentTestFolders -match '.*waf-aligned').count -eq 0) { $wafTestFilePath = Join-Path $testCasesPath 'waf-aligned' 'main.test.bicep' if ($PSCmdlet.ShouldProcess("file [$wafTestFilePath]", 'Add')) { $null = New-Item -Path $wafTestFilePath -ItemType 'File' -Force } $wafTestTemplateSourceFilePath = Join-Path $PSScriptRoot 'src' 'src.main.test.bicep' if (Test-Path $wafTestTemplateSourceFilePath) { $wafTestTemplateSourceFileContent = Get-Content -Path $wafTestTemplateSourceFilePath $suggestedServiceShort = '{0}waf' -f (($resourceTypeIdentifier -split '[\/|\\|-]' | ForEach-Object { $_[0] }) -join '') # e.g., npemin $wafTestTemplateSourceFileContent = $wafTestTemplateSourceFileContent -replace '<serviceShort>', $suggestedServiceShort $suggestedResourceGroupName = $resourceTypeIdentifier -replace '[\/|\\]', '.' -replace '-' # e.g., network.privateendpoints $wafTestTemplateSourceFileContent = $wafTestTemplateSourceFileContent -replace '<The test resource group name>', $suggestedResourceGroupName if ($PSCmdlet.ShouldProcess("content for file [$wafTestFilePath]", 'Set')) { $null = Set-Content -Path $wafTestFilePath -Value $wafTestTemplateSourceFileContent } } Write-Verbose "Added file [$wafTestFilePath]" -Verbose } } # Check if there are nested modules to handle (recursion) if ($CurrentLevelFolderPath -ne $FullModuleFolderPath) { # More children to handle $nextChild = ($FullModuleFolderPath -replace ('{0}[\/|\\]*' -f [Regex]::Escape($CurrentLevelFolderPath)) -split '[\/|\\]')[0] Set-ModuleFileAndFolderSetup -FullModuleFolderPath $FullModuleFolderPath -CurrentLevelFolderPath (Join-Path $CurrentLevelFolderPath $nextChild) } }