Public/Get-GitHistory.Tools.ps1

Function Get-GitHistory {
    <#
        .SYNOPSIS
            Converts gitlog output into structured format
        .DESCRIPTION
            Gets Commit data from gitlog and gets Tags.
            Orders Commit by their tag and outputs in a list of objects or a nested json document (use -asJson)
            You can also specify to only output history from the latest major/minor/build.
        .EXAMPLE
            Get-GitHistory -TagPrefix WebApp -asJson
        .EXAMPLE
            $json = Get-GitHistory -asJson
        .EXAMPLE
            $json = Get-GitHistory -asJson -Latest Major
            $json = Get-GitHistory -asJson -Latest Minor
            $json = Get-GitHistory -asJson -Latest Build
    #>

    [cmdletbinding()]

    param(
        [ValidateSet("Public", "Internal")]
        [string]
        $Audience
        ,
        [string]
        $WorkDir
        ,
        [int]
        $RequiredCommitMessageLength = 5
        ,
        [string]
        $ProjectName
        ,
        [string]
        $TagPrefix
        ,
        [string]
        $RemoteName = 'origin'
        ,
        [ValidateSet("psobject", "json","md","html")]
        [string] 
        $OutputAs
        ,
        [String]
        $Latest = ''
        # Specify to retrieve the latest Major, Minor, Build
        ,
        [switch]
        $toChangelog
    )
    # Settings
    Begin {
        # Ensuring Encoding
        $env:LC_ALL = 'C.UTF-8'
        [Console]::OutputEncoding = [System.Text.Encoding]::UTF8

        $CurrentBranch = $env:Build_SourceBranchName

        $config = Import-PowerShellDataFile -Path  $PSScriptRoot/../PSGitChangeLog.Config.psd1
        $Intents = $config.Intents
        
        $Omit = $config.Omit
    }
    Process {
        If (!$ProjectName) {
            $ProjectName = (Split-Path -Leaf (git remote get-url $RemoteName)).Replace('.git', '')
        }
        If ($WorkDir) { Set-Location $WorkDir }

        # Instantiate GitLog as an Object so that we can work with it
        If ($Latest) {
            $gitlog = (git log $CurrentBranch -500 --format="%ai`t%H`t%an`t%ae`t%s" )
        } Else {
            $gitlog = (git log --format="%ai`t%H`t%an`t%ae`t%s" )
        }
        $gitHist = $gitlog | ConvertFrom-Csv -Delimiter "`t" -Header ("Date", "CommitId", "Author", "Email", "Subject")

        $Releases = Get-GitTagList -TagPrefix $TagPrefix
        # Normalizing log entries
        $logs = @()

        $TagValue = 'Unreleased'

        $logs = ForEach ($Commit in $gitHist) {
            #Set the current Version/Tag in the history
            $tag = $Releases | Where-Object { $_.Commit -eq $Commit.commitid } | Select-Object -last 1
            if ($tag) {
                $TagValue = $tag.Tag
                $TagSemVerId = $tag.SemVerId
                $TagCommit = $tag.Commit
                $TagDate = $tag.Date
            }

            #Skip output if match with Omit
            If ($Omit | Where-Object { $Commit.Subject -match $_ }) { Continue }

            $IntentCode = $Intents.Code | Where-Object { $Commit.Subject -match $_ } | Select-Object -First 1
            If ( $null -eq $IntentCode) {
                $IntentCode = 'Other'
            }
            $Intent = $Intents | Where-Object { $_.Code -contains $IntentCode }            
            If ($Audience -eq 'Public' -and $Intent.DefaultAudience -eq 'internal') {
                Continue
            }
            If ($Commit.Subject.Length -lt $RequiredCommitMessageLength) {
                Write-Host "Commit message: $message is considered too short ($RequiredCommitMessageLength). Ommitting from changelog..."
                Continue
            }
            $IssueKey = Test-IssueKey($Commit.Subject)
            $log = [pscustomobject]@{
                Project          = $ProjectName
                Release          = $TagValue
                ReleaseVersionid = $TagSemVerId
                ReleaseCommit    = $TagCommit
                ReleaseDate      = $TagDate
                IntentCode       = $IntentCode
                Intent           = $Intent.Description
                Audience         = $Intent.DefaultAudience
                Message          = $Commit.Subject
                IssueKey         = $IssueKey
                CommitId         = $Commit.CommitId
                Order            = $Intents.Order
            }
            
            Write-Output $log
        } #ForEach

        If ($OutputAs -eq 'psobject') { return $logs }

        $Releasedata = @()

        If ($Latest) {
            $Major = $Releases.Major | Select-Object -first 1
            $Minor = ($Releases | Where-Object { $_.Major -eq $Major } ).Minor | Select-Object -first 1
            Write-Host "Getting Releases of Latest $Latest"
            If ($Latest -eq 'Build') {
                $Releases = $Releases | Select-Object -first 1
            } ElseIf ($Latest -eq 'Major') {
                $Major = $Releases.Major | Select-Object -first 1
                Write-Host "$latest $major"
                $Releases = $Releases | Where-Object { $_.Major -eq $Major }
            } ElseIf ($Latest -eq 'Minor') {
                Write-Host "$latest $Major.$Minor"
                $Releases = $Releases | Where-Object { $_.Major -eq $Major -and $_.Minor -eq $Minor }
            }
        }
        If ($logs | Where-Object { $_.Release -eq 'Unreleased' } ) {
            $Releasedata += [ordered]@{
                    Release       = 'Unreleased'
                    ReleaseDate   = ''
                    Component     = ''
                    Version       = ''
                    ReleaseCommit = ''
                    Commits       = $logs | Where-Object { $_.Release -eq 'Unreleased'} | SOrt-Object -Property Order | Select-Object -Property * -ExcludeProperty Project, Release, Order
                }
        }
        Write-Host $Releases.Count Releases
        $Releasedata += ForEach ($Release in $Releases) {
            [ordered]@{
                Release       = $Release.Tag
                ReleaseDate   = $Release.Date
                Component     = $Release.Component
                Version       = [string]$Release.SemVerId
                ReleaseCommit = $Release.Commit
                Commits       = $logs | Where-Object { $_.Release -eq $Release.Tag } | SOrt-Object -Property Order | Select-Object -Property * -ExcludeProperty Project, Release, Order
            }
        }

        $Data = @{
            Project  = $ProjectName
            Releases = $Releasedata
        }

        $Json = $Data | ConvertTo-Json -depth 4
        
        If ($OutputAs -eq 'json') { Return $json }

        If ($OutputAs -eq 'md'){
            $Changelog = ConvertTo-Changelog($Json) -FormatAs md
            Return $Changelog
        } elseif ($OutputAs -eq 'html') {
            $Changelog = ConvertTo-Changelog($Json) -FormatAs html
            Return $Changelog   
        }        
    }
}