Skip to content

Commit

Permalink
Updates to support telemetry and better prompts (#115)
Browse files Browse the repository at this point in the history
# Pull Request

## Issue

#114 

## Description

This PR makes no significant functional changes other than improving the
prompts users see for IaC, bootstrao and starter.

The primary update is to pull the bootstrap and starter from named
artefacts. By doing this we can get some usage telemetry from the GitHub
API.

Note that changes have been made to the starter and bootstrap repos for
Terraform to accommodate this, but all those changes are backwards
compatible and already released. They are ready to go with these changes
now.

## Testing

- E2E tests have be run for this branch here:
https://github.com/Azure/accelerator-bootstrap-modules/actions/runs/9414281487
- Manual testing of Terraform and Bicep happy paths has been completed
for prompt testing.


## License

By submitting this pull request, I confirm that my contribution is made
under the terms of the projects associated license.
  • Loading branch information
jaredfholgate authored Jun 7, 2024
1 parent cc905c8 commit 58015ba
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 82 deletions.
122 changes: 59 additions & 63 deletions src/ALZ/Private/Config-Helpers/Request-SpecialInput.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function Request-SpecialInput {
[string] $type,

[Parameter(Mandatory = $false)]
[string] $starterPath,
[PSCustomObject] $starterConfig,

[Parameter(Mandatory = $false)]
[PSCustomObject] $bootstrapModules,
Expand All @@ -17,83 +17,79 @@ function Request-SpecialInput {
if ($PSCmdlet.ShouldProcess("ALZ-Terraform module configuration", "modify")) {

$result = ""

if($null -ne $userInputOverrides) {
$userInputOverride = $userInputOverrides.PSObject.Properties | Where-Object { $_.Name -eq $type }
if($null -ne $userInputOverride) {
$result = $userInputOverride.Value
return $result
}
$options = @()
$aliasOptions = @()
$typeDescription = ""

if($type -eq "iac") {
$options += @{ key = "bicep"; name = "Bicep"; description = "Bicep" }
$options += @{ key = "terraform"; name = "Terraform"; description = "Terraform" }
$typeDescription = "Infrastructure as Code (IaC) language"
}

$gotValidInput = $false

while(!$gotValidInput) {
if($type -eq "starter") {

$starterFolders = Get-ChildItem -Path $starterPath -Directory
Write-InformationColored "Please select the starter module you would like to use, you can enter one of the following keys:" -ForegroundColor Yellow -InformationAction Continue

$starterOptions = @()
foreach($starterFolder in $starterFolders) {
if($starterFolder.Name -eq $starterPipelineFolder) {
continue
if($type -eq "bootstrap") {
if($bootstrapModules.PsObject.Properties.Name.Count -eq 0) {
$options += @{ key = "azuredevops"; name = "Azure DevOps"; description = "Azure DevOps" }
$options += @{ key = "github"; name = "GitHub"; description = "GitHub" }
$aliasOptions += @{ key = "alz_azuredevops"; name = "Azure DevOps"; description = "Azure DevOps" }
$aliasOptions += @{ key = "alz_github"; name = "GitHub"; description = "GitHub" }
} else {
foreach ($bootstrapModule in $bootstrapModules.PsObject.Properties) {
$options += @{ key = $bootstrapModule.Name; name = $bootstrapModule.Value.short_name; description = $bootstrapModule.Value.description }
foreach($alias in $bootstrapModule.Value.aliases) {
$aliasOptions += @{ key = $alias; name = $bootstrapModule.Value.short_name; description = $bootstrapModule.Value.description }
}
}
}
$typeDescription = "bootstrap module"
}

Write-InformationColored "- $($starterFolder.Name)" -ForegroundColor Yellow -InformationAction Continue
$starterOptions += $starterFolder.Name
if($type -eq "starter") {
foreach($starter in $starterConfig.starter_modules.PsObject.Properties) {
if($starter.Name -eq $starterPipelineFolder) {
continue
}

Write-InformationColored ": " -ForegroundColor Yellow -NoNewline -InformationAction Continue
$result = Read-Host
$options += @{ key = $starter.Name; name = $starter.Value.short_name; description = $starter.Value.description }
}
$typeDescription = "starter module"
}

if($result -notin $starterOptions) {
Write-InformationColored "The starter '$result' that you have selected does not exist. Please try again with a valid starter..." -ForegroundColor Red -InformationAction Continue
} else {
$gotValidInput = $true
if($null -ne $userInputOverrides) {
$userInputOverride = $userInputOverrides.PSObject.Properties | Where-Object { $_.Name -eq $type }
if($null -ne $userInputOverride) {
$result = $userInputOverride.Value
if($options.key -notcontains $result -and $aliasOptions.key -notcontains $result) {
Write-InformationColored "The $typeDescription '$result' that you have selected does not exist. Please try again with a valid $typeDescription..." -ForegroundColor Red -InformationAction Continue
throw "The $typeDescription '$result' that you have selected does not exist. Please try again with a valid $typeDescription..."
}
return $result
}
}

if($type -eq "iac") {
Write-InformationColored "Please select the IAC you would like to use, you can enter one of 'bicep or 'terraform': " -ForegroundColor Yellow -NoNewline -InformationAction Continue
$result = Read-Host

$validIac = @("bicep", "terraform")
if($result -notin $validIac) {
Write-InformationColored "The IAC '$result' that you have selected does not exist. Please try again with a valid IAC..." -ForegroundColor Red -InformationAction Continue
# Add the options to the choices array
$choices = @()
$usedLetters = @()
foreach($option in $options) {
$letterIndex = 0

} else {
$gotValidInput = $true
}
Write-Verbose "Checking for used letters in '$($option.name)'. Used letters: $usedLetters"
while($usedLetters -contains $option.name[$letterIndex].ToString().ToLower()) {
$letterIndex++
}

if($type -eq "bootstrap") {
Write-InformationColored "Please select the bootstrap module you would like to use, you can enter one of the following keys:" -ForegroundColor Yellow -InformationAction Continue

$bootstrapOptions = @()
if($bootstrapModules.PsObject.Properties.Name.Count -eq 0) {
$bootstrapOptions += "azuredevops"
Write-InformationColored "- azuredevops" -ForegroundColor Yellow -InformationAction Continue
$bootstrapOptions += "github"
Write-InformationColored "- github" -ForegroundColor Yellow -InformationAction Continue
} else {
foreach ($bootstrapModule in $bootstrapModules.PsObject.Properties) {
Write-InformationColored "- $($bootstrapModule.Name) ($($bootstrapModule.Value.description))" -ForegroundColor Yellow -InformationAction Continue
$bootstrapOptions += $bootstrapModule.Name
}
}
$usedLetters += $option.name[$letterIndex].ToString().ToLower()
$option.name = $option.name.Insert($letterIndex, "&")
$choices += New-Object System.Management.Automation.Host.ChoiceDescription $option.name, $option.description
}

Write-InformationColored ": " -ForegroundColor Yellow -NoNewline -InformationAction Continue
$result = Read-Host
$message = "Please select the $typeDescription you would like to use."
$title = "Choose $typeDescription"
$resultIndex = $host.ui.PromptForChoice($title, $message, $choices, 0)
$result = $options[$resultIndex].key

if($result -notin $bootstrapOptions) {
Write-InformationColored "The starter '$result' that you have selected does not exist. Please try again with a valid starter..." -ForegroundColor Red -InformationAction Continue
} else {
$gotValidInput = $true
}
}
}
Write-InformationColored "You selected '$result'. Continuing with deployment..." -ForegroundColor Green -InformationAction Continue

return $result
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ function Get-BootstrapAndStarterConfig {
$starterModuleSourceFolder = ""
$starterReleaseTag = ""
$starterPipelineFolder = ""
$starterReleaseArtifactName = ""
$starterConfigFilePath = ""

$bootstrapDetails = $null
$validationConfig = $null
Expand Down Expand Up @@ -61,8 +63,10 @@ function Get-BootstrapAndStarterConfig {
}

$starterModuleUrl = $starterModuleDetails.Value.$iac.url
$starterModuleSourceFolder = $starterModuleDetails.Value.$iac.module_path
$starterPipelineFolder = $starterModuleDetails.Value.$iac.pipeline_folder
$starterModuleSourceFolder = $starterModuleDetails.Value.$iac.release_artifact_root_path
$starterPipelineFolder = $starterModuleDetails.Value.$iac.release_artifact_ci_cd_path
$starterReleaseArtifactName = $starterModuleDetails.Value.$iac.release_artifact_name
$starterConfigFilePath = $starterModuleDetails.Value.$iac.release_artifact_config_file
}

# Get the bootstrap interface user input config
Expand All @@ -71,14 +75,16 @@ function Get-BootstrapAndStarterConfig {
$inputConfig = Get-ALZConfig -configFilePath $inputConfigFilePath

return @{
bootstrapDetails = $bootstrapDetails
hasStarterModule = $hasStarterModule
starterModuleUrl = $starterModuleUrl
starterModuleSourceFolder = $starterModuleSourceFolder
starterReleaseTag = $starterReleaseTag
starterPipelineFolder = $starterPipelineFolder
validationConfig = $validationConfig
inputConfig = $inputConfig
bootstrapDetails = $bootstrapDetails
hasStarterModule = $hasStarterModule
starterModuleUrl = $starterModuleUrl
starterModuleSourceFolder = $starterModuleSourceFolder
starterReleaseTag = $starterReleaseTag
starterPipelineFolder = $starterPipelineFolder
starterReleaseArtifactName = $starterReleaseArtifactName
starterConfigFilePath = $starterConfigFilePath
validationConfig = $validationConfig
inputConfig = $inputConfig
}
}
}
19 changes: 19 additions & 0 deletions src/ALZ/Private/Deploy-Accelerator-Helpers/Get-StarterConfig.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

function Get-StarterConfig {
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $false)]
[string]$starterPath,
[Parameter(Mandatory = $false)]
[string]$starterConfigPath
)

if ($PSCmdlet.ShouldProcess("Get Configuration for Bootstrap and Starter", "modify")) {
# Get the bootstap configuration
$starterConfigFullPath = Join-Path $starterPath $starterConfigPath
Write-Verbose "Starter config path $starterConfigFullPath"
$starterConfig = Get-ALZConfig -configFilePath $starterConfigFullPath

return $starterConfig
}
}
10 changes: 8 additions & 2 deletions src/ALZ/Private/Deploy-Accelerator-Helpers/New-Bootstrap.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ function New-Bootstrap {
[Parameter(Mandatory = $false)]
[string] $starterTargetPath,

[Parameter(Mandatory = $false)]
[PSCustomObject] $starterConfig = $null,

[Parameter(Mandatory = $false)]
[string] $bootstrapRelease,

Expand Down Expand Up @@ -83,8 +86,11 @@ function New-Bootstrap {
$pipelineModulePath = ""

if($hasStarter) {
$starter = Request-SpecialInput -type "starter" -starterPath $starterPath -userInputOverrides $userInputOverrides
$starterModulePath = Resolve-Path (Join-Path -Path $starterPath -ChildPath $starter)
$starter = Request-SpecialInput -type "starter" -starterConfig $starterConfig -userInputOverrides $userInputOverrides

Write-Verbose "Selected Starter: $starter"

$starterModulePath = Resolve-Path (Join-Path -Path $starterPath -ChildPath $starterConfig.starter_modules.$starter.location)
$pipelineModulePath = Resolve-Path (Join-Path -Path $starterPath -ChildPath $starterPipelineFolder)

Write-Verbose "Starter Module Path: $starterModulePath"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ function New-FolderStructure {
[Parameter(Mandatory = $false)]
[string] $release = "latest",

[Parameter(Mandatory = $false)]
[string] $releaseArtifactName = "",

[Parameter(Mandatory = $true)]
[string] $targetFolder,

Expand Down Expand Up @@ -43,7 +46,7 @@ function New-FolderStructure {
}

} else {
$releaseTag = Get-GithubRelease -githubRepoUrl $url -targetDirectory $targetDirectory -moduleSourceFolder $sourceFolder -moduleTargetFolder $targetFolder -release $release
$releaseTag = Get-GithubRelease -githubRepoUrl $url -targetDirectory $targetDirectory -moduleSourceFolder $sourceFolder -moduleTargetFolder $targetFolder -release $release -releaseArtifactName $releaseArtifactName
$path = Join-Path $targetDirectory $targetFolder $releaseTag
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ function New-ModuleSetup {
[Parameter(Mandatory = $false)]
[string]$release,
[Parameter(Mandatory = $false)]
[string]$releaseArtifactName = "",
[Parameter(Mandatory = $false)]
[string]$moduleOverrideFolderPath,
[Parameter(Mandatory = $false)]
[bool]$skipInternetChecks
Expand All @@ -28,6 +30,7 @@ function New-ModuleSetup {
-targetDirectory $targetDirectory `
-url $url `
-release $release `
-releaseArtifactName $releaseArtifactName `
-targetFolder $targetFolder `
-sourceFolder $sourceFolder `
-overrideSourceDirectoryPath $moduleOverrideFolderPath
Expand Down
27 changes: 22 additions & 5 deletions src/ALZ/Private/Shared/Get-GithubRelease.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ function Get-GithubRelease {
$moduleSourceFolder = ".",

[Parameter(Mandatory = $true, HelpMessage = "The target directory location of the modules.")]
$moduleTargetFolder
$moduleTargetFolder,

[Parameter(Mandatory = $false, HelpMessage = "The name of the release artifact in the target release. Defaults to standard release zip.")]
$releaseArtifactName = ""
)

$parentDirectory = $targetDirectory
Expand Down Expand Up @@ -110,7 +113,17 @@ function Get-GithubRelease {
Write-Verbose "===> Pulling and extracting release $releaseTag into $targetVersionPath"
New-Item -ItemType Directory -Path "$targetVersionPath/tmp" | Out-String | Write-Verbose
$targetPathForZip = "$targetVersionPath/tmp/$releaseTag.zip"
Invoke-WebRequest -Uri "https://github.com/$repoOrgPlusRepo/archive/refs/tags/$releaseTag.zip" -OutFile $targetPathForZip -RetryIntervalSec 3 -MaximumRetryCount 100 | Out-String | Write-Verbose

# Get the artifact url
if($releaseArtifactName -ne "") {
$releaseArtifactUrl = $releaseData.assets | Where-Object { $_.name -eq $releaseArtifactName } | Select-Object -ExpandProperty browser_download_url
} else {
$releaseArtifactUrl = $releaseData.zipball_url
}

Write-Verbose "===> Downloading the release artifact $releaseArtifactUrl from the GitHub repository $repoOrgPlusRepo"

Invoke-WebRequest -Uri $releaseArtifactUrl -OutFile $targetPathForZip -RetryIntervalSec 3 -MaximumRetryCount 100 | Out-String | Write-Verbose

if(!(Test-Path $targetPathForZip)) {
Write-InformationColored "Failed to download the release $releaseTag from the GitHub repository $repoOrgPlusRepo" -ForegroundColor Red -InformationAction Continue
Expand All @@ -120,11 +133,15 @@ function Get-GithubRelease {
$targetPathForExtractedZip = "$targetVersionPath/tmp/extracted"

Expand-Archive -Path $targetPathForZip -DestinationPath $targetPathForExtractedZip | Out-String | Write-Verbose
$extractedSubFolder = Get-ChildItem -Path $targetPathForExtractedZip -Directory

Write-Verbose "===> Copying all extracted contents into $targetVersionPath."
$extractedSubFolder = $targetPathForExtractedZip
if($releaseArtifactName -eq "") {
$extractedSubFolder = (Get-ChildItem -Path $targetPathForExtractedZip -Directory).FullName
}

Write-Verbose "===> Copying all extracted contents into $targetVersionPath from $($extractedSubFolder)/$moduleSourceFolder/*."

Copy-Item -Path "$($extractedSubFolder.FullName)/$moduleSourceFolder/*" -Destination "$targetVersionPath" -Recurse -Force | Out-String | Write-Verbose
Copy-Item -Path "$($extractedSubFolder)/$moduleSourceFolder/*" -Destination "$targetVersionPath" -Recurse -Force | Out-String | Write-Verbose

Remove-Item -Path "$targetVersionPath/tmp" -Force -Recurse
Write-InformationColored "The directory for $targetVersionPath has been created and populated." -ForegroundColor Green -InformationAction Continue
Expand Down
Loading

0 comments on commit 58015ba

Please sign in to comment.