ps/Modules/Cole.PowerShell.Developer/Public/Get-SemverHistory.ps1

231 lines
7.9 KiB
PowerShell
Raw Normal View History

2023-05-30 22:51:22 -07:00
function Get-SemverHistory {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[string]$Path = (Get-Location).Path
)
if ((Split-Path -Path $Path -Leaf) -eq 'sem.ver') {
# We have a semver file already
} else {
if (-not (Get-Item -Path $Path).PSIsContainer) {
throw "The Path argument should be a folder or a sem.ver specific file"
}
$Path = Join-Path -Path $Path -ChildPath "sem.ver"
$Path = (Get-ChildItem -Path $Path -Recurse | Select-Object -First 1).FullName
}
if (-not (Test-Path -Path $Path)) {
throw "Could not find the requested path [$Path]"
}
$semverLog = git log -c -- $Path
$commits = @()
$commit = $null
$inSemverLines = $false
foreach ($line in $semverLog) {
if ([string]::IsNullOrWhiteSpace($line)) {
continue
}
# This breaks if the comment starts with the word 'commit' on the left margin
if ($line.StartsWith("commit") -and [string]::IsNullOrWhiteSpace($Commit.SemverValue)) {
if ($null -ne $commit) {
$commits += $commit
}
$commit = @{
Hash = ($line -split 'commit ')[1].Trim()
Author = ""
Date = ""
SemverValue = ""
SemverContents = @()
Comment = @()
}
$inSemverLines = $false
} elseif ($line.StartsWith("Author:")) {
$commit.Author = ($line -split 'Author:')[1].Trim()
} elseif ($line.StartsWith("Date:")) {
$commit.Date = ($line -split 'Date:')[1].Trim()
} else {
if ($line.StartsWith("diff --git")) {
# We don't care about [diff --git a/sem.ver b/sem.ver] type lines
continue
} elseif ($line.StartsWith("index") -and ($line -split ' ').Count -eq 3) {
# we don't care about [index 7c4d2b4..e1de4ac 100644] type lines
continue
} elseif ($line.StartsWith("---") -or $line.StartsWith("+++")) {
# we don't care about the diff filenames
continue
} elseif ($line.StartsWith("@@") -and $line.EndsWith("@@")) {
$inSemverLines = $true
continue
} elseif ($inSemverLines) {
if ($line.Trim().StartsWith("-") -or $line.StartsWith("\")) {
# ignore remove lines
continue
} elseif ($line.Trim().StartsWith("+")) {
# skip the first two characters
$line = $line.Substring(2)
}
$commit.SemverContents += $line
} else {
$commit.Comment += $line.Trim()
}
}
}
# Save the last one too!
if ($null -ne $commit) {
$commits += $commit
}
foreach ($commit in $commits) {
# Yes, it's a hack. It's cheaper than retrieving the file _at_ the hash tho
$jsonString = "$($commit.SemverContents -join '')".Trim()
$jsonString = $jsonString.Replace(' ', '').Replace("`t", "")
if ([string]::IsNullOrWhiteSpace($jsonString)) {
continue
}
if (($jsonString.IndexOf("Version") -eq -1) -or ($jsonString.StartsWith('{"Major"'))) {
$jsonString = "`"Version`": {$jsonString"
}
if (-not $jsonString.StartsWith("{")) {
$jsonString = "{$jsonString"
}
if ($jsonString.StartsWith("{{")) {
$jsonString = $jsonString.Substring(1)
$jsonString = "{`"Version`":$jsonString"
}
if (-not $jsonString.EndsWith("}")) {
$jsonString = "$jsonString}"
}
if (-not $jsonString.EndsWith("}}")) {
$jsonString = "$jsonString}"
}
$jsonString = $jsonString.Replace(' {{', '{')
$json = ConvertFrom-Json $jsonString
$commit.SemverValue = "$($json.Version.Major).$($json.Version.Minor).$($json.Version.Patch)"
$commit.SemverContents = $null
}
return $commits
}
function Get-GitHistory {
[CmdletBinding()]
[OutputType([object[]])]
param (
[Parameter(Mandatory = $true, ParameterSetName = 'ByHash')]
[ValidateNotNullOrEmpty()]
[Alias('From')]
[string]$HashStart,
[Parameter(Mandatory = $true, ParameterSetName = 'ByHash')]
[ValidateNotNullOrEmpty()]
[Alias('To')]
[string]$HashEnd,
[Parameter(Mandatory = $true, ParameterSetName = 'ByObject')]
[Alias('FromEntry')]
[object]$StartEntry,
[Parameter(Mandatory = $true, ParameterSetName = 'ByObject')]
[Alias('ToEntry')]
[object]$EndEntry
)
$logLead = Get-LogLeadName
if ($PSCmdlet.ParameterSetName -eq 'ByHash') {
if ($HashStart -eq $HashEnd) {
Write-Error "$logLead : You must supply two different hashes. These hashes were the same."
return
}
$dateStart = Invoke-CallOperatorWithPathAndParameters git @('log', '--no-walk', '--format="%ai"', $HashStart)
$dateEnd = Invoke-CallOperatorWithPathAndParameters git @('log', '--no-walk', '--format="%ai"', $HashEnd)
# Put them in the right order
if ($dateStart -lt $dateEnd) {
$HashStart, $HashEnd = $HashEnd, $HashStart
}
} else {
if ($StartEntry.Date -lt $EndEntry.Date) {
$StartEntry, $EndEntry = $EndEntry, $StartEntry
}
$HashEnd = $EndEntry.Hash
$HashStart = $StartEntry.Hash
}
$lines = Invoke-CallOperatorWithPathAndParameters git @('log', "$HashEnd...$HashStart", '--format="Author: %aN%nDate: %ai%n%B%n-="', '--notes')
$results = @()
$result = $null
$skipAdd = $false
foreach ($line in $lines) {
if ($line.StartsWith("Author: ")) {
if ($null -ne $result) {
$results += $result
$skipAdd = $false
}
$result = @{
Author = $line.Substring(8)
Date = $null
Comments = @()
JiraTickets = @()
}
} elseif ($line.Trim() -eq '-=') {
if ($skipAdd -eq $false) {
$results += $result
}
$skipAdd = $false
$result = $null
} elseif ($line.StartsWith("Date: ")) {
$result.Date = [DateTime]($line.Substring(6))
} else {
$result.Comments += $line.Trim()
if ($line.StartsWith('Merge')) {
$skipAdd = $true
}
}
}
foreach ($result in $results) {
$result.JiraTickets = (Select-String '[A-Z]+-[0-9]+' -InputObject $result.Comments -AllMatches -CaseSensitive).Matches.Value
}
return $results
}
function Get-RepoHistoryBySemver {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[string]$Path = (Get-Location).Path
)
$results = @()
Write-Progress -Activity "Getting history for semver" -PercentComplete 1
$semverHistory = Get-SemverHistory -Path $Path
for ($i = 0; $i -lt ($semverHistory.Count - 1); $i++) {
$from = $semverHistory[$i]
$to = $semverHistory[$i + 1]
Write-Progress -Activity "Getting history by semver" -PercentComplete ((100 * $i) / ($semverHistory.Count - 1)) -Status "Checking for data between $($from.Hash) and $($to.Hash)"
$commitHistory = Get-GitHistory -StartEntry $from -EndEntry $to
$results += @{
Version = $from.SemverValue
JiraTickets = ($commitHistory.JiraTickets | Sort-Object -Unique)
CommitHistory = $commitHistory
CommitCount = $commitHistory.Count
SemverData = $from
}
}
Write-Progress -Completed -Activity "Getting history by semver"
return $results
}