Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions src/ALZ/Private/Deploy-Accelerator-Helpers/New-FolderStructure.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ function New-FolderStructure {
[switch] $replaceFiles,

[Parameter(Mandatory = $false)]
[int] $maxRetryCount = 10
[int] $maxRetryCount = 10,

[Parameter(Mandatory = $false)]
[int] $retryIntervalSeconds = 3,

[Parameter(Mandatory = $false)]
[int] $httpRequestTimeoutSeconds
)

if ($PSCmdlet.ShouldProcess("ALZ-Terraform module configuration", "modify")) {
Expand Down Expand Up @@ -54,7 +60,20 @@ function New-FolderStructure {
}

} else {
$releaseTag = Get-GithubRelease -githubRepoUrl $url -targetDirectory $targetDirectory -moduleSourceFolder $sourceFolder -moduleTargetFolder $targetFolder -release $release -releaseArtifactName $releaseArtifactName -maxRetryCount $maxRetryCount
$releaseParams = @{
githubRepoUrl = $url
targetDirectory = $targetDirectory
moduleSourceFolder = $sourceFolder
moduleTargetFolder = $targetFolder
release = $release
releaseArtifactName = $releaseArtifactName
maxRetryCount = $maxRetryCount
retryIntervalSeconds = $retryIntervalSeconds
}
if ($PSBoundParameters.ContainsKey("httpRequestTimeoutSeconds")) {
$releaseParams["httpRequestTimeoutSeconds"] = $httpRequestTimeoutSeconds
}
$releaseTag = Get-GithubRelease @releaseParams
$path = Join-Path $targetDirectory $targetFolder $releaseTag
}

Expand Down
69 changes: 47 additions & 22 deletions src/ALZ/Private/Deploy-Accelerator-Helpers/New-ModuleSetup.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ function New-ModuleSetup {
[Parameter(Mandatory = $false)]
[switch]$autoApprove,
[Parameter(Mandatory = $false)]
[int]$maxRetryCount = 10
[int]$maxRetryCount = 10,
[Parameter(Mandatory = $false)]
[int]$retryIntervalSeconds = 3,
[Parameter(Mandatory = $false)]
[int]$httpRequestTimeoutSeconds
)

if ($PSCmdlet.ShouldProcess("Check and get module", "modify")) {
Expand All @@ -44,21 +48,36 @@ function New-ModuleSetup {

if(-not [string]::IsNullOrWhiteSpace($moduleOverrideFolderPath)) {
Write-Verbose "Using module override folder path, skipping version checks."
return New-FolderStructure `
-targetDirectory $targetDirectory `
-url $url `
-release $desiredRelease `
-releaseArtifactName $releaseArtifactName `
-targetFolder $targetFolder `
-sourceFolder $sourceFolder `
-overrideSourceDirectoryPath $moduleOverrideFolderPath `
-replaceFiles:$replaceFiles.IsPresent `
-maxRetryCount $maxRetryCount
$folderParams = @{
targetDirectory = $targetDirectory
url = $url
release = $desiredRelease
releaseArtifactName = $releaseArtifactName
targetFolder = $targetFolder
sourceFolder = $sourceFolder
overrideSourceDirectoryPath = $moduleOverrideFolderPath
replaceFiles = $replaceFiles.IsPresent
maxRetryCount = $maxRetryCount
retryIntervalSeconds = $retryIntervalSeconds
}
if ($PSBoundParameters.ContainsKey("httpRequestTimeoutSeconds")) {
$folderParams["httpRequestTimeoutSeconds"] = $httpRequestTimeoutSeconds
}
return New-FolderStructure @folderParams
}

$latestReleaseTag = $null
try {
$latestResult = Get-GithubReleaseTag -githubRepoUrl $url -release "latest" -maxRetryCount $maxRetryCount
$releaseTagParams = @{
githubRepoUrl = $url
release = "latest"
maxRetryCount = $maxRetryCount
retryIntervalSeconds = $retryIntervalSeconds
}
if ($PSBoundParameters.ContainsKey("httpRequestTimeoutSeconds")) {
$releaseTagParams["httpRequestTimeoutSeconds"] = $httpRequestTimeoutSeconds
}
$latestResult = Get-GithubReleaseTag @releaseTagParams
$latestReleaseTag = $latestResult.ReleaseTag
Write-Verbose "Latest available $targetFolder version: $latestReleaseTag"
} catch {
Expand Down Expand Up @@ -136,16 +155,22 @@ function New-ModuleSetup {
Write-ToConsoleLog "Downloading $targetFolder module version $desiredRelease" -IsSuccess
}

$versionAndPath = New-FolderStructure `
-targetDirectory $targetDirectory `
-url $url `
-release $desiredRelease `
-releaseArtifactName $releaseArtifactName `
-targetFolder $targetFolder `
-sourceFolder $sourceFolder `
-overrideSourceDirectoryPath $moduleOverrideFolderPath `
-replaceFiles:$replaceFiles.IsPresent `
-maxRetryCount $maxRetryCount
$downloadFolderParams = @{
targetDirectory = $targetDirectory
url = $url
release = $desiredRelease
releaseArtifactName = $releaseArtifactName
targetFolder = $targetFolder
sourceFolder = $sourceFolder
overrideSourceDirectoryPath = $moduleOverrideFolderPath
replaceFiles = $replaceFiles.IsPresent
maxRetryCount = $maxRetryCount
retryIntervalSeconds = $retryIntervalSeconds
}
if ($PSBoundParameters.ContainsKey("httpRequestTimeoutSeconds")) {
$downloadFolderParams["httpRequestTimeoutSeconds"] = $httpRequestTimeoutSeconds
}
$versionAndPath = New-FolderStructure @downloadFolderParams

Write-Verbose "New version: $($versionAndPath.releaseTag) at path: $($versionAndPath.path)"

Expand Down
32 changes: 29 additions & 3 deletions src/ALZ/Private/Shared/Get-GithubRelease.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,31 @@ function Get-GithubRelease {

[Parameter(Mandatory = $false, HelpMessage = "Maximum number of retries for transient GitHub API errors.")]
[int]
$maxRetryCount = 10
$maxRetryCount = 10,

[Parameter(Mandatory = $false, HelpMessage = "Seconds to wait between retries for transient HTTP request errors.")]
[int]
$retryIntervalSeconds = 3,

[Parameter(Mandatory = $false, HelpMessage = "Timeout in seconds for HTTP requests.")]
[int]
$httpRequestTimeoutSeconds
)

$parentDirectory = $targetDirectory
$targetPath = Join-Path $targetDirectory $moduleTargetFolder

# Get the release tag and data from GitHub
$releaseResult = Get-GithubReleaseTag -githubRepoUrl $githubRepoUrl -release $release -maxRetryCount $maxRetryCount
$releaseTagParams = @{
githubRepoUrl = $githubRepoUrl
release = $release
maxRetryCount = $maxRetryCount
retryIntervalSeconds = $retryIntervalSeconds
}
if ($PSBoundParameters.ContainsKey("httpRequestTimeoutSeconds")) {
$releaseTagParams["httpRequestTimeoutSeconds"] = $httpRequestTimeoutSeconds
}
$releaseResult = Get-GithubReleaseTag @releaseTagParams
$releaseTag = $releaseResult.ReleaseTag
$releaseData = $releaseResult.ReleaseData

Expand Down Expand Up @@ -100,7 +117,16 @@ function Get-GithubRelease {

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

Invoke-GitHubApiRequest -Uri $releaseArtifactUrl -OutputFile $targetPathForZip -MaxRetryCount $maxRetryCount -RetryIntervalSeconds 3
$downloadParams = @{
Uri = $releaseArtifactUrl
OutputFile = $targetPathForZip
MaxRetryCount = $maxRetryCount
RetryIntervalSeconds = $retryIntervalSeconds
}
if ($PSBoundParameters.ContainsKey("httpRequestTimeoutSeconds")) {
$downloadParams["TimeoutSec"] = $httpRequestTimeoutSeconds
}
Invoke-GitHubApiRequest @downloadParams

if(!(Test-Path $targetPathForZip)) {
Write-ToConsoleLog "Failed to download the release $releaseTag from the GitHub repository $repoOrgPlusRepo" -IsError
Expand Down
21 changes: 19 additions & 2 deletions src/ALZ/Private/Shared/Get-GithubReleaseTag.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,15 @@ function Get-GithubReleaseTag {

[Parameter(Mandatory = $false, HelpMessage = "Maximum number of retries for transient GitHub API errors.")]
[int]
$maxRetryCount = 10
$maxRetryCount = 10,

[Parameter(Mandatory = $false, HelpMessage = "Seconds to wait between retries for transient HTTP request errors.")]
[int]
$retryIntervalSeconds = 3,

[Parameter(Mandatory = $false, HelpMessage = "Timeout in seconds for HTTP requests.")]
[int]
$httpRequestTimeoutSeconds
)

# Split Repo URL into parts
Expand All @@ -48,7 +56,16 @@ function Get-GithubReleaseTag {
}

# Query the GitHub API
$response = Invoke-GitHubApiRequest -Uri $repoReleaseUrl -SkipHttpErrorCheck -MaxRetryCount $maxRetryCount -RetryIntervalSeconds 3
$apiParams = @{
Uri = $repoReleaseUrl
SkipHttpErrorCheck = $true
MaxRetryCount = $maxRetryCount
RetryIntervalSeconds = $retryIntervalSeconds
}
if ($PSBoundParameters.ContainsKey("httpRequestTimeoutSeconds")) {
$apiParams["TimeoutSec"] = $httpRequestTimeoutSeconds
}
$response = Invoke-GitHubApiRequest @apiParams
$releaseData = $response.Result
$statusCode = $response.StatusCode

Expand Down
76 changes: 38 additions & 38 deletions src/ALZ/Private/Shared/Invoke-GitHubApiRequest.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
####################################
####################################
# Invoke-GitHubApiRequest.ps1 #
####################################
# Version: 0.1.0
Expand Down Expand Up @@ -65,6 +65,9 @@ function Invoke-GitHubApiRequest {
[Parameter(Mandatory = $false, HelpMessage = "If specified, downloads the response to this file path.")]
[string] $OutputFile,

[Parameter(Mandatory = $false, HelpMessage = "Timeout in seconds for the HTTP request.")]
[int] $TimeoutSec,

[Parameter(Mandatory = $false, HelpMessage = "If specified, does not throw on HTTP error status codes.")]
[switch] $SkipHttpErrorCheck
)
Expand All @@ -87,49 +90,46 @@ function Invoke-GitHubApiRequest {
Write-Verbose "GitHub CLI is not installed. Proceeding without authentication."
}

$isDownload = -not [string]::IsNullOrEmpty($OutputFile)
$transientStatusCodes = @(408, 429, 500, 502, 503, 504)
$maxAttempts = $MaxRetryCount + 1

for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) {
try {
if ($isDownload) {
Invoke-WebRequest -Uri $Uri -Method $Method -Headers $headers -OutFile $OutputFile -ErrorAction Stop
return
}

if ($SkipHttpErrorCheck) {
$result = Invoke-RestMethod -Uri $Uri -Method $Method -Headers $headers -SkipHttpErrorCheck -StatusCodeVariable "responseStatusCode"
# Build parameters for the generic retry cmdlet
$retryParams = @{
Uri = $Uri
Method = $Method
MaxRetryCount = $MaxRetryCount
RetryIntervalSeconds = $RetryIntervalSeconds
}

$code = [int]$responseStatusCode
if ($PSBoundParameters.ContainsKey("TimeoutSec")) {
$retryParams["TimeoutSec"] = $TimeoutSec
}

if ($code -in $transientStatusCodes -and $attempt -lt $maxAttempts) {
Write-Warning "Request to $Uri returned status $code (attempt $attempt of $maxAttempts). Retrying in $RetryIntervalSeconds seconds..."
Start-Sleep -Seconds $RetryIntervalSeconds
continue
}
if ($headers.Count -gt 0) {
$retryParams["Headers"] = $headers
}

return @{
Result = $result
StatusCode = $code
}
}
# File download — delegate directly
if (-not [string]::IsNullOrEmpty($OutputFile)) {
Invoke-HttpRequestWithRetry @retryParams -OutFile $OutputFile
return
}

return (Invoke-RestMethod -Uri $Uri -Method $Method -Headers $headers -ErrorAction Stop)
} catch {
$responseCode = $null
if ($_.Exception.Response) {
$responseCode = [int]$_.Exception.Response.StatusCode
}
# API call with SkipHttpErrorCheck — parse JSON and return Result/StatusCode hashtable
if ($SkipHttpErrorCheck) {
$response = Invoke-HttpRequestWithRetry @retryParams -SkipHttpErrorCheck -ReturnStatusCode

$isTransient = $responseCode -in $transientStatusCodes
$parsed = $null
if (-not [string]::IsNullOrWhiteSpace($response.Result.Content)) {
$parsed = $response.Result.Content | ConvertFrom-Json
}

if ($isTransient -and $attempt -lt $maxAttempts) {
Write-Warning "Request to $Uri failed with status $responseCode (attempt $attempt of $maxAttempts). Retrying in $RetryIntervalSeconds seconds..."
Start-Sleep -Seconds $RetryIntervalSeconds
} else {
throw
}
return @{
Result = $parsed
StatusCode = $response.StatusCode
}
}

# Standard API call — parse JSON and return the object
$response = Invoke-HttpRequestWithRetry @retryParams
if (-not [string]::IsNullOrWhiteSpace($response.Content)) {
return ($response.Content | ConvertFrom-Json)
}
}
Loading
Loading