Modules/AzureDevOpsDsc.Common/Resources/Functions/Public/AzDoReleaseFolder/Remove-AzDoReleaseFolder.ps1

<#
.SYNOPSIS
Removes an Azure DevOps classic Release folder.
 
.DESCRIPTION
Deletes the folder. Deleting a release folder deletes every release definition beneath it, so a
folder that still has contents is left alone unless AllowRecursiveDelete is set. Without that
guard, narrowing a configuration to remove one folder would take an arbitrary number of release
definitions with it.
 
Throws rather than writing a non-terminating error when the folder cannot safely be removed, so a
caller applying this resource via Invoke-DscResource sees the refusal rather than Set() reporting
success while later Test() calls report drift with no visible reason.
 
.PARAMETER ProjectName
The name of the Azure DevOps project.
 
.PARAMETER Path
The full path of the Release folder.
 
.PARAMETER Description
The folder description.
 
.PARAMETER AllowRecursiveDelete
Permit deletion of a folder that still contains release definitions or sub-folders.
 
.PARAMETER LookupResult
The lookup result supplied by the DSC base class.
 
.PARAMETER Ensure
The desired state, supplied by the DSC base class.
 
.PARAMETER Force
Forces the operation, supplied by the DSC base class.
 
.EXAMPLE
Remove-AzDoReleaseFolder -ProjectName 'Contoso' -Path '\Platform' -AllowRecursiveDelete $true
#>

Function Remove-AzDoReleaseFolder
{
    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSObject[]])]
    param
    (
        [Parameter(Mandatory = $true)]
        [Alias('Name')]
        [System.String]$ProjectName,

        [Parameter(Mandatory = $true)]
        [Alias('FolderPath')]
        [System.String]$Path,

        [Parameter()]
        [AllowEmptyString()]
        [System.String]$Description,

        [Parameter()]
        [System.Boolean]$AllowRecursiveDelete,

        [Parameter()]
        [HashTable]$LookupResult,

        [Parameter()]
        [Ensure]$Ensure,

        [Parameter()]
        [System.Management.Automation.SwitchParameter]$Force
    )

    Write-Verbose "[Remove-AzDoReleaseFolder] Started."

    $organization   = Get-AzDoOrganizationName
    $normalizedPath = Format-AzDoPipelineFolderPath -Path $Path

    if ($normalizedPath -eq '\')
    {
        throw "[Remove-AzDoReleaseFolder] The project release root cannot be removed."
    }

    $folders = List-DevOpsReleaseFolders -Organization $organization -ProjectName $ProjectName -Path $normalizedPath
    $folder  = $folders | Where-Object { (Format-AzDoPipelineFolderPath -Path $_.path) -eq $normalizedPath } | Select-Object -First 1

    if ($null -eq $folder)
    {
        Write-Verbose "[Remove-AzDoReleaseFolder] Release folder '$normalizedPath' does not exist. Nothing to remove."
        return
    }

    if (-not $AllowRecursiveDelete)
    {
        # Anything listed beneath this path other than the folder itself means the delete would
        # take definitions or sub-folders with it.
        $children = @($folders | Where-Object { (Format-AzDoPipelineFolderPath -Path $_.path) -ne $normalizedPath })

        try
        {
            $definitions = Get-DevOpsReleaseDefinitionsInFolder -Organization $organization -ProjectName $ProjectName -Path $normalizedPath
        }
        catch
        {
            # Emptiness could not be established, so the guard cannot be satisfied. Refusing is
            # the safe outcome: the alternative is deleting release definitions on the strength
            # of a failed lookup.
            throw "[Remove-AzDoReleaseFolder] Could not determine whether release folder '$normalizedPath' is empty, so it has not been removed. Error: $_"
        }

        if ($children.Count -gt 0 -or (@($definitions).Count -gt 0))
        {
            throw "[Remove-AzDoReleaseFolder] Release folder '$normalizedPath' in project '$ProjectName' is not empty. Deleting it would delete every release definition and sub-folder beneath it. Set AllowRecursiveDelete = `$true to permit this."
        }
    }
    else
    {
        Write-Warning "[Remove-AzDoReleaseFolder] Recursively deleting release folder '$normalizedPath' and everything beneath it."
    }

    Write-Verbose "[Remove-AzDoReleaseFolder] Removing release folder '$normalizedPath'."

    return (Remove-DevOpsReleaseFolder -Organization $organization -ProjectName $ProjectName -Path $normalizedPath)
}