Private/Get-CpmfUipsGitMetadata.ps1

function Get-CpmfUipsGitMetadata {
<#
.SYNOPSIS
    Returns repository URL, branch and short commit for a project directory.
 
.DESCRIPTION
    Repository metadata is per-repo and computed fresh at pack time rather than
    stored in shared publisher identity. This helper is best-effort: a project
    outside a git repository, a missing git executable, or a detached/remote-less
    checkout all yield an empty hashtable rather than an error.
 
    Keys, when available: RepositoryUrl, RepositoryBranch, RepositoryCommit.
 
.PARAMETER Path
    Directory inside the git repository (typically the project directory).
#>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param(
        [Parameter(Mandatory)]
        [string]$Path
    )

    $result = @{}

    # A failed lookup here is expected and harmless, but git's exit code would
    # otherwise leak out of the module and look like a pack failure to a CI
    # script that checks $LASTEXITCODE.
    $priorExitCode = $global:LASTEXITCODE

    if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
        Write-Verbose '[GitMetadata] git not found on PATH — skipping repository metadata.'
        return $result
    }

    $queries = [ordered]@{
        RepositoryUrl    = @('remote', 'get-url', 'origin')
        RepositoryBranch = @('rev-parse', '--abbrev-ref', 'HEAD')
        RepositoryCommit = @('rev-parse', '--short', 'HEAD')
    }

    foreach ($key in $queries.Keys) {
        try {
            $value = (& git -C $Path @($queries[$key]) 2>$null | Select-Object -First 1)
            if ($LASTEXITCODE -eq 0 -and -not [string]::IsNullOrWhiteSpace($value)) {
                $result[$key] = $value.Trim()
            }
        } catch {
            Write-Verbose "[GitMetadata] $key lookup failed: $($_.Exception.Message)"
        }
    }

    if ($result.Count -eq 0) {
        Write-Verbose "[GitMetadata] No repository metadata available for $Path"
    }

    $global:LASTEXITCODE = $priorExitCode

    return $result
}