tasks/bicep.tasks.ps1
$BaseBranch = "origin/main" $BicepRegistryFqdn = $env:BicepRegistryFqdn $RegistryPath = $env:RegistryPath $BicepTemplatesDir = $SourcesDir $BicepModulesDir = "" $OverwriteTag = $false $AlwaysTag = $false $RequiredBicepCliVersion = "" $MinimumBicepCliVersion = "0.8.9" function getAllBicepFiles { [CmdletBinding()] param ( [Parameter()] [string] $Path = $BicepTemplatesDir ) Write-Verbose "Looking for Bicep templates in '$Path'" Get-ChildItem -Recurse -Filter *.bicep -Path $Path } function getChangedBicepModules { $changedModules = git diff $BaseBranch --name-only | Where-Object { $_.StartsWith("modules") } | ForEach-Object { $split = $_ -split "/"; $split[1..2] -join "/" } | Where-Object { $_.Contains("/") } | Where-Object { Test-path $BicepModulesDir/$_ } | Select-Object -Unique Write-Host "Changed modules:`n$($changedModules -join "`n")" $changedModules } # Synopsis: Lints Bicep files and builds the ARM template task BuildBicepFiles ` -Partial ` -Inputs { getAllBicepFiles } ` -Outputs { process { [System.IO.Path]::ChangeExtension($_, 'json')} } ` -Jobs InstallBicepTooling,{ begin { $failBuild = $false } process { Write-Build White "Building: $_" & az bicep build -f $_ if ($LASTEXITCODE -ne 0) { $failBuild = $true } } end { if ($failBuild) { throw "Bicep build error(s) - check preceeding log messages" } else { Write-Build Green "Bicep files OK" } } } # Synopsis: Installs Bicep CLI and Bicep Registry Module tooling task InstallBicepTooling -If { getAllBicepFiles } DetectBuildServer,{ Write-Build White "Checking Bicep CLI version:" $script:currentBicepVersion = $null $currentVersionBanner = try { & bicep --version } catch {} if ($currentVersionBanner) { Write-Build White $currentVersionBanner if ($currentVersionBanner -imatch "\d+(\.\d+)+") { $script:currentBicepVersion = [version]$Matches[0] Write-Build White $currentBicepVersion } } else { Write-Warning "Bicep tooling is not installed" } # Implement the comparison logic for the required & minimum version scenarios # A required version takes precedent over a minimum version if ($RequiredBicepCliVersion) { Write-Build White "Checking for exact Bicep version $RequiredBicepCliVersion" $currentVersionOk = $currentBicepVersion -eq [version]$RequiredBicepCliVersion } else { Write-Build White "Checking for minimum Bicep version $MinimumBicepCliVersion" $currentVersionOk = $currentBicepVersion -ge [version]$MinimumBicepCliVersion } # Only install Bicep CLI if it's not already installed or if it's an older version if (!$currentBicepVersion -or !$currentVersionOk ) { if ($IsRunningOnBuildServer) { $bitness = [System.Environment]::Is64BitOperatingSystem ? "x64" : "x86" if ($IsMacOS) { $downloadFile = "bicep-osx-$bitness" } elseif ($IsLinux) { $downloadFile = "bicep-linux-$bitness" } else { $downloadFile = "bicep-win-$bitness.exe" } # Setup temporary folder for Bicep CLI installation $destPath = $IsWindows ? "$($env:TEMP)/bicepcli/bicep" : "/tmp/bicepcli/bicep" New-Item -ItemType Directory (Split-Path -Path $destPath) -EA 0 | Out-Null # Determine which version to download based on whether an exact or minimum version has been specified $versionToDownload = $RequiredBicepCliVersion ? "v$RequiredBicepCliVersion" : "v$MinimumBicepCliVersion" $downloadUrl = "https://github.com/Azure/bicep/releases/download/$versionToDownload/$downloadFile" Write-Build White "Downloading Bicep CLI: $downloadUrl ==> $destPath" $res = Invoke-WebRequest ` -Uri $downloadUrl ` -OutFile $destPath if ($IsMacOS -or $IsLinux) { & chmod +x $destPath } Write-Build White "Updating PATH to use the newly-installed Bicep CLI" $env:PATH = "{0}{1}{2}" -f ` (Split-Path -Parent $destPath), [IO.Path]::PathSeparator, $env:PATH Get-Command bicep | Out-String | Write-Build White # Record the Bicep version that has been installed $script:currentBicepVersion = [version]$versionToDownload.TrimStart("v") } else { if ($RequiredBicepCliVersion) { throw ("Bicep tooling mismatch. Required version is '$RequiredBicepCliVersion', please update your installed version. [CurrentVersion=$currentBicepVersion]") } else { throw ("Bicep tooling mismatch. Minimum version is '$MinimumBicepCliVersion', please update your installed version. [CurrentVersion=$currentBicepVersion]") } } } # Ensure the Bicep Registry Module tool is installed with a version consistent with the installed version of the Bicep CLI Write-Build White "Ensuring matching version of 'brm' tool" Install-DotNetTool Azure.Bicep.RegistryModuleTool -Version $currentBicepVersion.ToString() } # Synopsis: Installs the Nerdbank GitVersion global tool task InstallNbgvTool { Install-DotNetTool nbgv } # Synopsis: Validates all Bicep modules via 'brm validate' task ValidateBicepModules -If { $BicepModulesDir } ` -Inputs { getAllBicepFiles -Path $BicepModulesDir | ? { !$_.FullName.EndsWith(".test.bicep") } } ` -Outputs "always-run" ` -Jobs InstallBicepTooling,{ begin { $passed = $true } process { Push-Location (Split-Path -Parent $_) Write-Build White "Validating $_" & brm validate if ($LASTEXITCODE -ne 0) { $passed = $false } Pop-Location } end { if (!$passed) { throw "Validation failed for one more modules - check previous logs" } else { Write-Build Green "All Bicep modules validated successfully" } } } # synopsis: Updates generated content for Bicep modules via 'brm generate' task RunBrmGenerate -If { $BicepModulesDir } ` -Inputs { getAllBicepFiles -Path $BicepModulesDir | ? { !$_.FullName.EndsWith(".test.bicep") } } ` -Outputs "always-run" ` -Jobs InstallBicepTooling,{ begin { $passed = $true } process { Push-Location (Split-Path -Parent $_) Write-Build White "Regenerating $_" & brm generate if ($LASTEXITCODE -ne 0) { $passed = $false } Pop-Location } end { if (!$passed) { throw "Generation failed for one more modules - check previous logs" } else { Write-Build Green "All Bicep modules regenerated successfully" } } } # Synopsis: Publishes any updated Bicep modules via 'bicep publish' task PublishBicepModules -If { $BicepModulesDir } ` -Inputs { getAllBicepFiles | ? { !$_.FullName.EndsWith(".test.bicep") } } ` -Outputs "always-run" ` -Jobs InstallBicepTooling,InstallNbgvTool, { # validate publish details if (!$BicepRegistryFqdn) { throw "The 'BicepRegistryFqdn' variables has not been defined" } elseif (!$BicepRegistryFqdn.EndsWith(".azurecr.io")) { throw "The 'BicepRegistryFqdn' must point to an Azure Container Registry with the '.azurecr.io' suffix - current value: $BicepRegistryFqdn" } # Publishing Bicep modules requires a logged-in Azure-Cli session if (!(Test-AzCliConnection)) { throw "You must be logged-in to azure-cli to publish Bicep modules to a private registry" } $modulesToPublish = getChangedBicepModules $gitTagsToPush = $false foreach ($module in $modulesToPublish) { Write-Build White "Processing module: $module" # Derive next version using nbgv Push-Location $BicepModulesDir/$module $res = & nbgv get-version --format json Pop-Location if ($res -eq $null) { Write-Warning "Error deriving version for '$module'" continue } $nbgvResults = $res | ConvertFrom-Json $semver = $nbgvResults.SemVer2 [bool]$isPublicRelease = $nbgvResults.PublicRelease # Publish to ACR $moduleRegistryFullPath = "$BicepRegistryFqdn/$RegistryPath/$($module):$semver" bicep publish "$BicepModulesDir/$module/main.json" --target "br:$moduleRegistryFullPath" if ($LASTEXITCODE -ne 0) { Write-Warning "Error publishing module '$module' to '$moduleRegistryFullPath'" continue } Write-Build Green " Published - OK" # Create/push tag $tag = "$module/$semver" # Tag all 'public releases' as identified by nbgv or when explicitly requested if ($isPublicRelease -or $AlwaysTag) { # By default don't update existing git tags if ($OverwriteTag) { Write-Build White " Any existing tag will be updated" & git tag -f $tag } else { & git tag $tag } if ($LASTEXITCODE -ne 0) { Write-Warning "Error tagging module '$module' with '$tag'" continue } $gitTagsToPush = $true Write-Build Green " Tagging - OK" } else { Write-Build White " Tagging - Skipped" } } if ($gitTagsToPush) { Write-Build White "Pushing module tags..." if ($OverwriteTag) { Write-Build White " Any existing tag will be updated" & git push --tags -f } else { & git push --tags } if ($LASTEXITCODE -ne 0) { Write-Warning "Error pushing modules' git tags to remote repo" } else { Write-Build Green "Pushed module tags - OK" } } else { Write-Build White "No module tags to push" } } # Synopsis: Build for running locally that includes regenerating module content files task LocalBicepBuild RunBrmGenerate,FullBuild |