Functions/New-ReleaseVersion.ps1
<#PSScriptInfo
.VERSION 1.1 .GUID d8aefbbf-d092-433b-8baa-3db3256a8734 .AUTHOR Artsiom Krot .COPYRIGHT Copyright (c) 2019 Artsiom Krot. All rights reserved. Script file name: New-ReleaseVersion.ps1 .DESCRIPTION The script is an integral part of PS.GitFlow solution (https://github.com/artyom-krot/PS.Gitflow) #> Function New-ReleaseVersion { <# .SYNOPSIS PowerShell script for generating release version number according with the Gitflow and semver standard. .DESCRIPTION This function generates release version according with the semver standards and Gitflow workflow. Version generation logic: ================================================================================================ Case 1# sourceGitBranch hotfix/{taskNumber}-{short description [0-9A-Za-z-]*}: Info: hotfix branch should be created only for the release, that currently used in production. After release was deployed on production the code should be merged from release/{majorVersion}.{minorVersion} to master and tag to be applied tag=release/{majorVersion}.{minorVersion}.{patchVersion} Validate latest release tag in the repository. Increase patch version based on the version in most recent release tag Case 2# sourceGitBranch = release/{majorVersion}.{minorVersion}: check existance of any release tag get the version from the current release branch case a. If tag is missing, apply current version from the source branch (Example: release/1.0 => releaseVersion should be 1.0.0) case b. If tag exists, apply {majorVersion}.{minorVersion} from the tag and increase patch version. (Example: release/1.0 and tag=1.1.0 => release_version should be 1.1.1) Case 3# sourceGitBranch = develop case a. If there is no any release/* branch, default release version 0.1.0 will be applied case b. If most recent release/* branch exist, apply {majorVersion} from release branch and increase minor version {minorVersion} + 1 (Example: release/1.0 and release/1.1 branches are present => releaseVersion 1.2.0 will be generated) Info: patch version always should be 0 for the version from develop branch. Case 4# sourceGitBranch feature/{taskNumber}-{short description [0-9A-Za-z-]*}: The same logic as for develop branch will be applied, because feature/* branches should be created from develop branch only. Case 5# sourceGitBranch bugfix/{taskNumber}-{short description [0-9A-Za-z-]*}: case a. If bugfix branch was created from develop branch, than the same logic as for develop branch will be applied. (Example: develop - branche is source branch for the bugfix; most recent release branch - release/1.0 => releaseVersion 1.1.0 will be generated) case b. If bugfix branch was created from release/{majorVersion}.{minorVersion} branch, than version {majorVersion}.{minorVersion} from the release branch will be applied and patch version will be increases {majorVersion}.{minorVersion}.1 (Example: most recent release branch - release/1.1 => releaseVersion 1.1.1 will be generated) Case 6# sourceGitBranch = master: check existance of any release tag get the version from the latest release tag case a. If tag is missing, apply default initial release version (Example: releaseVersion will be 0.1.0) case b. If tag exists, apply {majorVersion}.{minorVersion} from the tag. (Example: tag = release/1.0.1 => release_version should be 1.0.1) ================================================================================================ .INPUTS -rootGitDir <string[]> -sourceGitBranch <string[]> -refCommitId <string[]> .OUTPUTS variable $releaseVersion with release version value .NOTES .EXAMPLE New-ReleaseVersion -rootGitDir C:\gitrepos\myrepo -sourceGitBranch refs/heads/develop -refCommitId 1a532017421e8dsf4d3f18ec1ddc5fe4e655d575 Major Minor Build Revision ----- ----- ----- -------- 0 1 0 -1 #> param( [parameter(Position = 0, Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-Path -Path $_ -PathType Container })] [string] $rootGitDir, [parameter(Position = 1, Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $sourceGitBranch, [parameter(Position = 2, Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $refCommitId ) #region functions Function Get-LastReleaseTag { # Ensure proper sorting in case patchVersion has more than one digit $semVerFormat = @{Expression={if ($_ -match '(\d+)\.(\d+).(\d+)') {[int]$Matches[3]}}; Ascending=$true} try { # get most recent git tag $lastGitTag = [array](git tag -l "release/*" | Sort-Object -Property $semVerFormat | Select-Object -Last 1) } catch { Write-Warning "Last git tag is not avaliable"; } return $lastGitTag } #endregion functions #region main $initialLocation = Get-Location Set-Location $rootGitDir Write-Verbose "Root directory: $rootGitDir." Write-Verbose "Processing Branch: $sourceGitBranch." $sourceBranchName = $sourceGitBranch.Replace('refs/heads/', '') Write-Verbose "List all avaliable remote branches for the current git repo: $rootGitDir" try { $remoteBranchesList = @() git branch -r | ForEach-Object { $remoteBranchesList += $_.Trim() } } catch { $Host.UI.WriteErrorLine("Remote branches list is not avaliable!") Write-error "$($_.Exception.Message)" } # Case 1# sourceGitBranch hotfix/{taskNumber}-{short description [0-9A-Za-z-]*} if ($sourceBranchName -like "hotfix/*") { Write-Verbose "Processing source branch name: $sourceBranchName." # get most recent release/ tag $lastGitTag = Get-LastReleaseTag if ($lastGitTag) { Write-Verbose "Last git tag: $lastGitTag" [version]$lastGitTagVer = $lastGitTag | split-path -leaf Write-Verbose "Increse Patch version accoring with the latest tag version" # define releaseVersion $releaseVersion = "$($lastGitTagVer.Major).$($lastGitTagVer.Minor).$($lastGitTagVer.Build + 1)" } } # Case 2# sourceGitBranch = release/{majorVersion}.{minorVersion} elseif ($sourceBranchName -match "^release\/\d+\.\d+$") { Write-Verbose "Processing source branch name: $sourceBranchName." [version]$releaseVersion = $sourceBranchName | split-path -leaf Write-Verbose "Current release version $releaseVersion" # define releaseVersion [version]$releaseVersion = "$($releaseVersion.Major).$($releaseVersion.Minor).0" # get most recent release/ tag $lastGitTag = Get-LastReleaseTag if ($lastGitTag) { Write-Verbose "Last tag: $lastGitTag" [version]$lastGitTagVer = $lastGitTag | split-path -leaf $lastGitTagCommitIdReference = git rev-list -n 1 $lastGitTag Write-Verbose "CommitId = $lastGitTagCommitIdReference pointing to the last tag $lastGitTag." if ($lastGitTagVer -ge $releaseVersion) { if($lastGitTagCommitIdReference -eq $refCommitId) { Write-Verbose "Release version corresponds to latest tag version for the reference commitId=$($refCommitId)" [version]$releaseVersion = $lastGitTagVer } else { Write-Verbose "Increse Patch version according with the latest tag version" [version]$releaseVersion = "$($lastGitTagVer.Major).$($lastGitTagVer.Minor).$($lastGitTagVer.Build +1)" } } } } # Case 3# sourceGitBranch = develop # and # Case 4# sourceGitBranch feature/{taskNumber}-{short description [0-9A-Za-z-]*} elseif ($sourceBranchName -like "develop" -or $sourceBranchName -like "feature/*") { # Ensure proper sorting in cases when versions have more than one digit $semVerMajor = @{Expression={if ($_ -match '(\d+)\.(\d+)') {[int]$Matches[1]}}; Ascending=$true} $semVerMinor = @{Expression={if ($_ -match '(\d+)\.(\d+)') {[int]$Matches[2]}}; Ascending=$true} Write-Verbose "Processing source branch name: $sourceBranchName." $latestReleaseBranch = [array]($remoteBranchesList | Where-Object { $_ -like "*release/*" } | Sort-Object -Property $semVerMajor, $semVerMinor | Select-Object -Last 1) if($latestReleaseBranch) { Write-Verbose "Most recent release branch: $latestReleaseBranch" [version]$latestReleaseVersion = ($latestReleaseBranch | split-path -leaf) Write-Verbose "Increse minor version accoring to the most recent release branch $($latestReleaseBranch)" [version]$releaseVersion = "$($latestReleaseVersion.Major).$($latestReleaseVersion.Minor+1).0" } else { Write-Verbose "No any release/* branches detected. The default release version 0.1.0 will be applied." [version]$releaseVersion = "0.1.0" } } # Case 5# sourceGitBranch bugfix/{taskNumber}-{short description [0-9A-Za-z-]*} elseif ($sourceBranchName -like "bugfix/*") { Write-Verbose "Processing source branch name: $sourceBranchName." # get fork point with develop branch try { $forkPoint = git merge-base --fork-point origin/develop origin/$sourceGitBranch } Catch { $_.Exception; } # exitsing forkPoint means that current bugfix branch has been created from develop branch and versioning logic develop branch should be applied if (-Not [string]::IsNullOrEmpty($forkPoint)) { # Ensure proper sorting once versions will have more than one digit $major = @{Expression={if ($_ -match '(\d+)\.(\d+)') {[int]$Matches[1]}}; Ascending=$true} $minor = @{Expression={if ($_ -match '(\d+)\.(\d+)') {[int]$Matches[2]}}; Ascending=$true} $latestReleaseBranch = [array]($remoteBranchesList | Where-Object { $_ -like "*release/*" } | Sort-Object -Property $major, $minor | Select-Object -Last 1) if($latestReleaseBranch) { Write-Verbose "Most recent release branch: $latestReleaseBranch" [version]$latestReleaseVersion = ($latestReleaseBranch | split-path -leaf) Write-Verbose "Increse minor version accoring to the most recent release branch $($latestReleaseBranch)" [version]$releaseVersion = "$($latestReleaseVersion.Major).$($latestReleaseVersion.Minor+1).0" } else { Write-Verbose "No any release/* branches detected. The default release version 0.1.0 will be applied." [version]$releaseVersion = "0.1.0" } } # in case bugfix branch was created from release/* branch, patch version should be increased. else { $allReleaseBranches = $remoteBranchesList.Replace("origin/","") | Where-Object { $_ -like "*release/*" } foreach ($releaseBranch in $allReleaseBranches) { $forkPoint = git merge-base --fork-point origin/$releaseBranch origin/$sourceGitBranch # apply version according with the release branch that has fork point with bugfix branch and increase patch version if (-Not [string]::IsNullOrEmpty($forkPoint)) { Write-Verbose "Reference release branch: $releaseBranch" [version]$latestReleaseVersion = ($releaseBranch | split-path -leaf) Write-Verbose "Increse patch version accoring to the most recent release branch $($releaseBranch)" [version]$releaseVersion = "$($latestReleaseVersion.Major).$($latestReleaseVersion.Minor).1" } } } } # Case 6# sourceGitBranch = master elseif ($sourceBranchName -like "master") { Write-Verbose "Processing source branch name: $sourceBranchName." # get most recent release/ tag $lastGitTag = Get-LastReleaseTag if ($lastGitTag) { Write-Verbose "Last tag: $lastGitTag" [version]$lastGitTagVer = $lastGitTag | split-path -leaf $lastGitTagCommitIdReference = git rev-list -n 1 $lastGitTag Write-Verbose "CommitId = $lastGitTagCommitIdReference pointing to the last tag $lastGitTag." Write-Verbose "Release version corresponds to latest tag version for the reference commitId=$($refCommitId)" [version]$releaseVersion = $lastGitTagVer } else { Write-Warning "No any release tags were detected in the current repository" Write-Verbose "Default release version 0.1.0 will be applied." [version]$releaseVersion = "0.1.0" } } # In case of wrong branch name was used, throw an exception else { Write-Error "Type of the branch $sourceGitBranch could not be defined!"; Write-Warning "Please validate branch name."; Exit 1; } Write-Verbose "Generated release version: $releaseVersion" #get back to the previous location Set-Location $initialLocation # set new environment variable releaseVersion $Env:releaseVersion = $releaseVersion return $releaseVersion #endregion main } |