tasks/bicep.tasks.ps1

$BaseBranch = "origin/main"
$BicepRegistryFqdn = $env:BicepRegistryFqdn
$RegistryPath = $env:RegistryPath
$OverwriteTag = $false
$AlwaysTag = $false

function getAllBicepFiles {
    Get-ChildItem -Recurse -Filter *.bicep -Path $BicepModulesDir
}

function getChangedBicepModules {
    $changedModules = git diff $BaseBranch --name-only |
        Where-Object { $_.StartsWith("modules") } | 
        ForEach-Object { $split = $_ -split "/"; $split[1..2] -join "/" } |
        Where-Object { Test-path $here/modules/$_ } |
        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 {
        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 the Bicep Registry Module global tool
task InstallBrmTool {
    Install-DotNetTool Azure.Bicep.RegistryModuleTool
}

# Synopsis: Installs the Nerdbank GitVersion global tool
task InstallNbgvTool {
    Install-DotNetTool nbgv
}

# Synopsis: Validates all Bicep modules via 'brm validate'
task ValidateBicepModules `
    -Inputs { getAllBicepFiles | ? { !$_.FullName.EndsWith(".test.bicep") } } `
    -Outputs "always-run" `
    -Jobs InstallBrmTool,{
        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 `
    -Inputs { getAllBicepFiles | ? { !$_.FullName.EndsWith(".test.bicep") } } `
    -Outputs "always-run" `
    -Jobs InstallBrmTool,{
        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 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 modules/$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 "modules/$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