Last active
February 18, 2018 08:15
-
-
Save worldspawn/f34c51fe4450d2c5e862fbd954ecf628 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
param([Parameter(Mandatory=$true)]$mainRepo, [Parameter(Mandatory=$true)]$buildCount) | |
$types = @{ | |
"patch" = @{Title = "PATCH"; Order = 2 }; | |
"change" = @{Title = "CHANGE"; Order = 0 }; | |
"bug" = @{Title = "BUG"; Order = 3 }; | |
"feat" = @{Title = "FEATURE"; Order = 1 }; | |
"feature" = @{Title = "FEATURE"; Order = 1 }; | |
"hotfix" = @{Title = "HOTFIX"; ORDER = 0}; | |
}; | |
$separator = "<<>>"; | |
function New-Version() { | |
param ($currentVersion) | |
$matches = $null | |
$currentVersion -match "^v?(?:(?<major>\d+)\.)?(?:(?<minor>\d+)\.)?(?<patch>\*|\d+)?(?:\-(?<release>[A-Za-z0-9\.]+))?(?:\+(?<meta>[A-Za-z0-9\.]+))?$" | Out-Null | |
#$groups = [regex]::matches($currentVersion, "^(?:(?<major>\d+)\.)?(?:(?<minor>\d+)\.)?(?<patch>\*|\d+)?(?:\.(?<build>\d+))?(?:\-(?<release>[A-Za-z0-9\.]+))?(?:\+(?<meta>[A-Za-z0-9\.]+))?$") | |
$major = [convert]::ToInt32($matches.major) | |
$minor = [convert]::ToInt32($matches.minor) | |
$patch = [convert]::ToInt32($matches.patch) | |
if ($matches.release -eq $null) { | |
$release = @() | |
} | |
else { | |
$release = $matches.release.split('.') | |
} | |
if ($matches.meta -eq $null) { | |
$meta = @() | |
} | |
else { | |
$meta = $matches.meta.split('.') | |
} | |
$version = new-object PSObject | select-object Major, Minor, Patch, Build, Release, Meta | |
$version.Major = $major | |
$version.Minor = $minor | |
$version.Patch = $patch | |
if ($release -eq $null) { | |
$version.Release = @() | |
} | |
else { | |
$version.Release = $release | |
} | |
if ($meta -eq $null) { | |
$version.Meta = @() | |
} | |
else { | |
$version.Meta = $meta | |
} | |
return $version | |
} | |
function VersionAsString () { | |
param ($version) | |
$v = "$($version.Major).$($version.Minor).$($version.Patch)" | |
if ($version.Release.Count -gt 0) { | |
$v += "-" | |
$v += $version.Release -join '.' | |
} | |
if ($version.Meta.Count -gt 0) { | |
$v += "+" | |
$v += $version.Meta -join '.' | |
} | |
return $v | |
} | |
function Get-Messages() { | |
param($folder, | |
$currentbranch, | |
$mastertag) | |
$log = git -C $folder @("log", "--format=%%ct$separator%%Bxxx-xxx", "$mastertag..$currentbranch") | |
$results = New-Object -TypeName System.Collections.Generic.List[string] | |
$releaseNote = "" | |
foreach ($logItem in $log) { | |
if ($logItem -eq "xxx-xxx") { | |
$results.Add("$releaseNote`r`n") | |
$releaseNote = "" | |
continue | |
} | |
$items = $logItem -split $separator | |
if ($items.Length -eq 2) { | |
$timestamp = $items[0]; | |
$message = $items[1]; | |
} | |
else { | |
$message = $items[0]; | |
} | |
$transformed = $false | |
foreach ($item in $types.GetEnumerator()) { | |
if ($message -notlike "$($item.key)*(*)*") { | |
continue | |
} | |
$start = $message.IndexOf("(") + 1 | |
$end = $message.IndexOf(")") | |
$type = $item.value.Title | |
$header = $message.substring($start, $end - $start) | |
$releaseNote = "$timestamp$separator$type - $header" | |
$transformed = $true | |
break; | |
} | |
if ($transformed -eq $false) { | |
if ($releaseNote.Length -ne 0) { | |
$releaseNote = "$releaseNote`r`n$logItem" | |
} | |
else { | |
$releaseNote = "$timestamp$($separator)OTHER - $message" | |
} | |
} | |
} | |
return $results | |
} | |
function GenerateReleaseNotesAndVersionNumber() { | |
param($mainRepo) | |
Write-Host "Fetching in $($mainRepo.Path)" | |
git -C $mainRepo.Path fetch --all --tags -v | Out-Null | |
$lastmastertag = git -C $mainRepo.Path @("describe", "origin/master", "--tags", "--abbrev=0") | |
Write-Host "$($mainRepo.Name) - Master Tag: $lastmastertag" | |
$versionObj = New-Version $lastmastertag | |
#get the main repo information | |
$mainRepo.Branch = git -C $mainRepo.Path rev-parse --abbrev-ref HEAD | |
$mainRepo.Messages = Get-Messages $mainRepo.Path $mainRepo.Branch $lastmastertag | |
$mainRepo.Hash = git -C $mainRepo.Path rev-parse --short $mainRepo.Branch | |
foreach ($subRepo in $mainRepo.SubRepos) { | |
$subRepo.Branch = git -C $subRepo.Path rev-parse --abbrev-ref HEAD | |
$subRepo.Messages = Get-Messages $subRepo.Path $subRepo.Branch $lastmastertag | |
$subRepo.Hash = git -C $subRepo.Path rev-parse --short $subRepo.Branch | |
} | |
$branchNames = @(, $mainRepo.Branch) + @(, $mainRepo.SubRepos.Branch) | |
if (($branchNames | Get-Unique | Measure-Object).Count -eq 1) { | |
$currentbranch = $mainRepo.Branch | |
$currenthash = $mainRepo.Hash | |
} | |
#if the main branch is a feature branch that has commits | |
elseif ($mainRepo.Branch -ne "develop" -and $mainRepo.Messages.Count -ne 0) { | |
$currentbranch = $mainRepo.Branch | |
$currenthash = $mainRepo.Hash | |
} | |
else { | |
#for the extra repos, find the first one that is not develop that has commits | |
foreach ($subRepo in $mainRepo.SubRepos) { | |
if ($subRepo.Branch -ne "develop" -and $subRepo.Messages.Count -ne 0) { | |
$currentbranch = $subRepo.Branch | |
$currenthash = $subRepo.Hash | |
break; | |
} | |
} | |
} | |
Write-Host "$($mainRepo.Name) - Branch: $currentbranch" | |
Write-Host "$($mainRepo.Name) - Hash $currenthash" | |
$tmpAll = New-Object -TypeName System.Collections.Generic.List[Object] | |
$tmpAll.AddRange(@($mainRepo.Messages)) | |
foreach ($extraRepo in $mainRepo.SubRepos) { | |
if ($extraRepo.Messages -ne $null) { | |
$tmpAll.AddRange(@($extraRepo.Messages)) | |
} | |
} | |
$allMsgs = $tmpAll | ForEach-Object {@(, ($_ -split $separator))} | Select-Object @{Name = "timestamp"; Expression = {[int]$_[0]}}, @{Name = "message"; Expression = {$_[1]}} | Group-Object message | ForEach-Object { $_.Group[0] } | |
# These are ordered by Timestamp | |
$versionMsgs = $allMsgs | Sort-Object -Property timestamp | Select-Object -ExpandProperty message | |
# These are ordered by Message priority | |
$releaseNoteMsgs = $allMsgs | Sort-Object -Property @{Expression = { | |
foreach ($item in $types.GetEnumerator()) { | |
if ($_.message -like "$($item.Value.Title)*") { | |
return $item.Value.Order | |
} | |
} | |
return 99 | |
}; Ascending = $true | |
} | Select-Object -ExpandProperty message | |
foreach ($item in $versionMsgs) { | |
if ($item -like "CHANGE*") { | |
$versionObj.Major += 1; | |
$versionObj.Minor = 0; | |
$versionObj.Patch = 0; | |
} | |
elseif ($item -like "FEATURE*") { | |
$versionObj.Minor += 1; | |
$versionObj.Patch = 0; | |
} | |
elseif ($item -LIKE "PATCH*" -or $item -LIKE "BUG*" -or $item -LIKE "HOTFIX*") { | |
$versionObj.Patch += 1; | |
} | |
} | |
if ($currentbranch -ne "develop" -and $currentbranch -ne "master") { | |
$maxBranchLength = 2 + 7 + $build_count.toString().length #two dots + hash + build no | |
$maxBranchLength = 20 - $maxBranchLength | |
if ($currentbranch.Length -gt $maxBranchLength) { | |
$currentbranch = $currentbranch.substring(0, $maxBranchLength); | |
} | |
$versionObj.Release = @() | |
$versionObj.Release += $currentbranch | |
$versionObj.Release += $build_count | |
$versionObj.Release += $currenthash | |
} | |
else { | |
$versionObj.Release = @($build_count) | |
$versionObj.Release += $currenthash | |
} | |
$versionObj.Meta = @() | |
$version = VersionAsString($versionObj) | |
return @{ | |
Version = $version; | |
ReleaseNotes = $releaseNoteMsgs | |
} | |
} | |
$error.Clear(); | |
try { | |
$isLocal = $false; | |
$build_count = $buildCount | |
} | |
catch { | |
#we must be on a local machine | |
$build_count = 5000 | |
$isLocal = $true; | |
} | |
$error.Clear(); | |
$mainRepos = @( | |
@{ | |
Name = "$mainRepo"; | |
DisplayName = "$mainRepo"; | |
Path = ".\"; | |
Branch = ""; | |
Hash = ""; | |
Messages = $null; | |
IsTCVersion = $true; | |
SubRepos = @(); | |
} | |
) | |
try { | |
#fix git host name checking | |
$mainRepos | ForEach-Object { | |
if (!$isLocal) { | |
git -C $_.Path config core.sshCommand 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' | |
$_.SubRepos | ForEach-Object { | |
git -C $_.Path config core.sshCommand 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' | |
} | |
} | |
} | |
$releaseNotes = $mainRepos | ForEach-Object { | |
$results = GenerateReleaseNotesAndVersionNumber $_ | |
if ($_.IsTCVersion -eq $true) { | |
Write-Host "Build Number: $($results.Version)" | |
Write-Host "##teamcity[buildNumber '$($results.Version)']" | |
} | |
if ($results.ReleaseNotes.Length -eq 0) { | |
return @() | |
} | |
return @( | |
"#NAME", | |
$_.DisplayName, | |
"##VERSION", | |
$results.Version, | |
"##RELEASE NOTES", | |
$results.ReleaseNotes, | |
"---" | |
) | |
} | |
$releaseNotes | Out-File .\releasenotes.txt | |
} | |
finally { | |
#unset git hostname checking | |
$mainRepos | ForEach-Object { | |
if (!$isLocal) { | |
git -C $_.Path config --unset core.sshCommand | |
$_.SubRepos | ForEach-Object { | |
git -C $_.Path config --unset core.sshCommand | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment