Extensions/Git.Remote.UGit.Extension.ps1
<# .Synopsis Git Remotes Extension .Description Outputs git remotes as objects. .EXAMPLE git remote .EXAMPLE git remote | git remote get-url .EXAMPLE git remote | git remote show #> [Management.Automation.Cmdlet("Out","Git")] # It's an extension for Out-Git [ValidatePattern("^git remote")] # that is run when the command starts with git remote. [OutputType('git.remote.name','git.remote.uri', 'git.remote')] param( ) begin { $remoteLines = @() } process { $remoteLines += $_ } end { if ($gitArgument -match '--(?>n|dry-run)' -or # If the arguments matched --n or --dry-run or $remoteLines[0] -like 'usage:*' # the output lines started with usage: ) { return $remoteLines # return the output directly. } # git remote can do a few different things switch -Regex ($gitCommand) { 'git remote\s{0,}$' { # With no other parameters, it returns the remote name. return [PSCustomObject][Ordered]@{ PSTypename = 'git.remote.name' RemoteName = $remoteLines -join ' ' -replace '\s' GitRoot = $gitRoot } } 'git remote get-url (?<RemoteName>\S+)\s{0,}$' { # With get-url, it returns the URL return [PSCustomObject][Ordered]@{ PSTypename = 'git.remote.url' RemoteName = $matches.RemoteName RemoteUrl = $remoteLines -join ' ' -replace '\s' GitOutputLines = $remoteLines GitRoot = $gitRoot } } 'git remote show (?<RemoteName>\S+)\s{0,}$' { # With show, it returns _a lot_ of stuff. We want to track: $remoteName = $matches.RemoteName # * Each named URL $gitRemoteUrls = [ordered]@{ PSTypeName = 'git.remote.urls' } # * All remote branches $remoteBranches = @() # * All local branches $localBranches = @() # * All tracked upstream branches $trackedUpstreams = @() # * The Head branch $headBranch = '' $inSection = '' # We go thru each line returned by git remote show foreach ($line in $remoteLines) { if ($line -match '^\*\sremote\s(?<RemoteName>\S+)') { # We can ignore the first line (we already know the remote name) } elseif ($line -match 'URL:') { # Lines containing URL: can be split into a purpose and URL. $purpose, $remoteUrl = $line -split 'URL:' $gitRemoteUrls[$purpose -replace '\s'] = $remoteUrl -replace '\s' } elseif ($line -match '^\s{1,}HEAD branch:') { # The head branch line is helpfully marked. $headBranch = $line -replace '^\s{1,}HEAD branch:' -replace '\s' } elseif ($line -match '^\s{2}Remote Branches:') { # as are the names of each section $inSection = 'Remote Branches' } elseif ($line -match "^\s{2}Local branches configured for 'git pull':") { $inSection = 'LocalBranches' } elseif ($line -match "^\s{2}Local refs configured for 'git push':") { $inSection = 'LocalRefs' } elseif ($inSection -and $line -match '^\s{4}') { # Within each section, we'll want capture a branch name and status if ($inSection -eq 'Remote Branches') { $remoteBranch, $status, $null = $line -split '\s{1,}' -ne '' $remoteBranches += [PSCustomObject][Ordered]@{ PSTypename = 'git.remote.branch' BranchName = $remoteBranch Status = $status } } elseif ($inSection -eq 'Local Branches') { $localBranch, $status = $line -split '\s{1,}' -ne '' $status = $status -join ' ' $localBranches += [PSCustomObject][Ordered]@{ PSTypename = 'git.remote.local.branch' BranchName = $localBranch Status = $status } } elseif ($inSection -eq 'LocalRefs') { $localBranch, $status = $line -split '\s{1,}' -ne '' $status = $status -join ' ' $trackedUpstreams += [PSCustomObject][Ordered]@{ PSTypename = 'git.remote.tracked.upstream' BranchName = $localBranch Status = $status } } } } # Now we can return a custom object with all of the data from git.remote.show, and let the formatter do the work. return [PSCustomObject][Ordered]@{ PSTypename = 'git.remote.show' RemoteName = $remoteName HeadBranch = $headBranch RemoteURLs = [PSCustomObject]$gitRemoteUrls RemoteBranches = $remoteBranches LocalBranches = $localBranches TrackedUpstreams = $trackedUpstreams GitOutputLines = $remoteLines GitRoot = $gitRoot } } default { # If it wasn't any scenario we know how to parse, return the lines as-is. return $remoteLines } } } |