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(
        $Level
        ,
        $WorkDir
        ,
        $RequiredCommitMessageLength = 5
        ,
        $ProjectName
        ,
        $TagPrefix
        ,
        [string]
        $RemoteName = 'origin'
        ,
        [switch] $asJson
        ,
        [String]
        $Latest = ''
        # Specify to retrieve the latest Major, Minor, Build
    )
    # Settings
    Begin {
        # Ensuring Encoding
        $env:LC_ALL = 'C.UTF-8'
        [Console]::OutputEncoding = [System.Text.Encoding]::UTF8

        $CurrentBranch = $env:Build_SourceBranchName

        $CommitCodes = @(
            @{
                code            = '🐛', '🚑', 'bf:', 'bug:', 'prob:'
                description     = 'Bugs, Problems'
                DefaultAudience = 'all'
                Order           = 2
            }, @{
                code            = '👌', '📦', '✨', 'new:', 'impr:'
                description     = 'New features, Improvements'
                DefaultAudience = 'all'
                Order           = 1
            }, @{
                code            = '👷‍♂️', '⚙', '✅', 'ci:', 'cfg:', 'adm:', '💚'
                description     = 'Configuration, Testing'
                DefaultAudience = 'internal'
                Order           = 4
            }, @{
                code            = '📝'
                description     = 'Documentation'
                DefaultAudience = 'internal'
                Order           = 3
            }, @{
                code            = '✏', '♻', '🎨', 'rf:', 'opt:'
                description     = 'Code Optimization, Refactoring'
                DefaultAudience = 'all'
                Order           = 5
            }, @{
                code            = 'Other'
                description     = 'Other'
                DefaultAudience = 'all'
                Order           = 6
            }
        )
        $Omit = 'RE:', 'Merged', 'azure-pipelines.yml edited online with Bitbucket'
    }
    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 = ''

        $logs = ForEach ($Commit in $gitHist) {
            #$commit = $gitHist | select-object -first 1

            #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 }

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

        If (!$asJSON) { 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 }
            }
        }
        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
            }
        }

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

        $output = $Json | ConvertTo-Json -depth 4

        Return $output

    }
}