Modules/businessdev.ALbuild.Marketplace/Private/Select-BcIngestionBaseResource.ps1

function Select-BcIngestionBaseResource {
    <#
    .SYNOPSIS
        Picks the BASE-variant resource out of a Partner Center ingestion collection.
 
    .DESCRIPTION
        Partner Center partitions several ingestion collections BY VARIANT: an offer that has an AppSource
        Test Drive (or plan variants) gets its own package branch, package configuration and property
        resource per variant, each tagged with a 'variantID'. An offer without variants returns exactly
        one, variant-less resource.
 
        The submission flow used to take element [0] of those collections. That is correct only for a
        variant-less offer: on an offer WITH a variant it can select the variant-scoped resource, and the
        submission then fails with
 
            VariantNotFound - Variant '<name>' not found for product <id>
 
        because the referenced variant no longer exists (a Test Drive that was removed leaves the branch
        behind). This is why the 365 business Address Validation release failed while Banking / ERiC /
        E-Invoice / Sanction Screen - which have no variants - all succeeded.
 
        Selection is therefore explicit: the resource with NO variantID (the base/main variant) wins; if
        every candidate is variant-scoped, the caller decides via -AllowVariant. Every candidate is logged
        so a wrong pick is visible in the build log instead of surfacing as an opaque 400.
 
    .PARAMETER Resource
        The normalised resource collection (pipe through ConvertTo-BcResourceList first).
 
    .PARAMETER Description
        What is being selected, for the log/error text (e.g. 'package branch').
 
    .PARAMETER AllowVariant
        When no base-variant resource exists, return the first variant-scoped one (with a warning) instead
        of throwing. Use where a variant-scoped resource is still workable.
 
    .OUTPUTS
        The selected resource object.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $Resource,
        [Parameter(Mandatory)] [string] $Description,
        [switch] $AllowVariant
    )
    Set-StrictMode -Off

    $candidates = @($Resource | Where-Object { $_ })
    if ($candidates.Count -eq 0) { throw "No $Description found for the product." }

    # StrictMode-safe read: an absent 'variantID' must read as empty, not throw.
    $variantOf = {
        param($item)
        if ($item -and $item.PSObject.Properties['variantID'] -and $item.variantID) { "$($item.variantID)" } else { '' }
    }

    if ($candidates.Count -gt 1) {
        $described = @($candidates | ForEach-Object {
                $v = & $variantOf $_
                $id = if ($_.PSObject.Properties['id']) { "$($_.id)" } else { '(no id)' }
                "$id$(if ($v) { " [variant '$v']" } else { ' [base]' })"
            })
        Write-ALbuildLog "Product has $($candidates.Count) $Description(s): $($described -join ', ')."
    }

    $base = @($candidates | Where-Object { -not (& $variantOf $_) })
    if ($base.Count -gt 0) {
        if ($candidates.Count -gt 1) { Write-ALbuildLog "Using the base-variant $Description." }
        return $base[0]
    }

    $variantNames = (@($candidates | ForEach-Object { & $variantOf $_ }) | Sort-Object -Unique) -join ', '
    if ($AllowVariant) {
        Write-ALbuildLog -Level Warning "No base-variant $Description; falling back to variant '$(& $variantOf $candidates[0])'."
        return $candidates[0]
    }
    throw ("Every $Description of this product belongs to a variant ('$variantNames') - there is no base-variant one to submit against. " +
        "Partner Center rejects a submission that references a variant which no longer exists (VariantNotFound). " +
        "Remove the stale variant (e.g. a deleted Test Drive) from the offer in Partner Center, or restore it, then re-run the release.")
}