Skip to content

Commit

Permalink
Merge pull request #374 from freddydk/issue360
Browse files Browse the repository at this point in the history
Release Branches
  • Loading branch information
freddydk authored Jan 25, 2023
2 parents 99973e9 + a484f02 commit 3bd828f
Show file tree
Hide file tree
Showing 20 changed files with 434 additions and 75 deletions.
5 changes: 4 additions & 1 deletion Actions/CheckForUpdates/CheckForUpdates.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,10 @@ try {

# Set current location to the repository folder
Set-Location -Path *


# checkout branch to update
invoke-git checkout $updateBranch

# If $directCommit, then changes are made directly to the default branch
if (!$directcommit) {
# If not direct commit, create a new branch with a random name, and switch to it
Expand Down
23 changes: 19 additions & 4 deletions Actions/CreateReleaseNotes/CreateReleaseNotes.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,28 @@ try {
import-module (Join-Path -path $PSScriptRoot -ChildPath "..\TelemetryHelper.psm1" -Resolve)
$telemetryScope = CreateScope -eventId 'DO0074' -parentTelemetryScopeJson $parentTelemetryScopeJson

$releaseNotes = ""

Import-Module (Join-Path $PSScriptRoot '..\Github-Helper.psm1' -Resolve)

SemVerStrToSemVerObj -semVerStr $tag_name | Out-Null
# Check that tag is SemVer
$SemVerObj = SemVerStrToSemVerObj -semVerStr $tag_name

# Calculate release branch
$releaseBranch = "release/$($SemVerObj.Prefix)$($SemVerObj.Major).$($SemVerObj.Minor)"
if ($SemVerObj.Patch -or $SemVerObj.addt0 -ne 'zzz') {
$releaseBranch += ".$($SemVerObj.Patch)"
if ($SemVerObj.addt0 -ne 'zzz') {
$releaseBranch += "-$($SemVerObj.addt0)"
1..4 | ForEach-Object {
if ($SemVerObj."addt$($_)" -ne 'zzz') {
$releaseBranch += ".$($SemVerObj."addt$($_)")"
}
}
}
}
Add-Content -Path $env:GITHUB_OUTPUT -Value "releaseBranch=$releaseBranch"
Write-Host "releaseBranch=$releaseBranch"

$latestRelease = GetLatestRelease -token $token -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY
$latestRelease = GetLatestRelease -token $token -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY -ref $ENV:GITHUB_REF_NAME

$latestReleaseTag = ""
if ($latestRelease -and ([bool]($latestRelease.PSobject.Properties.name -match "tag_name"))){
Expand Down
3 changes: 3 additions & 0 deletions Actions/CreateReleaseNotes/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ inputs:
description: Tag name
required: true
outputs:
ReleaseBranch:
description: Name of the release branch
value: ${{ steps.createreleasenotes.outputs.ReleaseBranch }}
ReleaseNotes:
description: Release note generated based on the changes
value: ${{ steps.createreleasenotes.outputs.ReleaseNotes }}
Expand Down
116 changes: 95 additions & 21 deletions Actions/Github-Helper.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -304,11 +304,26 @@ function invoke-git {
cmdDo -command git -arguments $arguments -silent:$silent -returnValue:$returnValue -inputStr $inputStr
}

# Convert a semantic version object to a semantic version string
#
# The SemVer object has the following properties:
# Prefix: 'v' or ''
# Major: the major version number
# Minor: the minor version number
# Patch: the patch version number
# Addt0: the first additional segment (zzz means not specified)
# Addt1: the second additional segment (zzz means not specified)
# Addt2: the third additional segment (zzz means not specified)
# Addt3: the fourth additional segment (zzz means not specified)
# Addt4: the fifth additional segment (zzz means not specified)
#
# Returns the SemVer string
# # [v]major.minor.patch[-addt0[.addt1[.addt2[.addt3[.addt4]]]]]
function SemVerObjToSemVerStr {
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
$semVerObj
)

try {
$str = "$($semVerObj.Prefix)$($semVerObj.Major).$($semVerObj.Minor).$($semVerObj.Patch)"
for ($i=0; $i -lt 5; $i++) {
Expand All @@ -323,34 +338,80 @@ function SemVerObjToSemVerStr {
}
}

# Convert a semantic version string to a semantic version object
# SemVer strings supported are defined under https://semver.org, additionally allowing a leading 'v' (as supported by GitHub semver sorting)
#
# The string has the following format:
# if allowMajorMinorOnly is specified:
# [v]major.minor.[patch[-addt0[.addt1[.addt2[.addt3[.addt4]]]]]]
# else
# [v]major.minor.patch[-addt0[.addt1[.addt2[.addt3[.addt4]]]]]
#
# Returns the SemVer object. The SemVer object has the following properties:
# Prefix: 'v' or ''
# Major: the major version number
# Minor: the minor version number
# Patch: the patch version number
# Addt0: the first additional segment (zzz means not specified)
# Addt1: the second additional segment (zzz means not specified)
# Addt2: the third additional segment (zzz means not specified)
# Addt3: the fourth additional segment (zzz means not specified)
# Addt4: the fifth additional segment (zzz means not specified)

function SemVerStrToSemVerObj {
Param(
[string] $semVerStr
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string] $semVerStr,
[switch] $allowMajorMinorOnly
)

$obj = New-Object PSCustomObject
try {
# Only allowed prefix is a 'v'.
# This is supported by GitHub when sorting tags
$prefix = ''
$verstr = $semVerStr
if ($semVerStr -like 'v*') {
$prefix = 'v'
$verStr = $semVerStr.Substring(1)
}
# Next part is a version number with 2 or 3 segments
# 2 segments are allowed only if $allowMajorMinorOnly is specified
$version = [System.Version]"$($verStr.split('-')[0])"
if ($version.Revision -ne -1) { throw "not semver" }
if ($version.Build -eq -1) {
if ($allowMajorMinorOnly) {
$version = [System.Version]"$($version.Major).$($version.Minor).0"
$idx = $semVerStr.IndexOf('-')
if ($idx -eq -1) {
$semVerStr = "$semVerStr.0"
}
else {
$semVerstr = $semVerstr.insert($idx, '.0')
}
}
else {
throw "not semver"
}
}
# Add properties to the object
$obj | Add-Member -MemberType NoteProperty -Name "Prefix" -Value $prefix
$obj | Add-Member -MemberType NoteProperty -Name "Major" -Value ([int]$version.Major)
$obj | Add-Member -MemberType NoteProperty -Name "Minor" -Value ([int]$version.Minor)
$obj | Add-Member -MemberType NoteProperty -Name "Patch" -Value ([int]$version.Build)
0..4 | ForEach-Object {
# default segments to 'zzz' for sorting of SemVer Objects to work as GitHub does
$obj | Add-Member -MemberType NoteProperty -Name "Addt$_" -Value 'zzz'
}
$idx = $verStr.IndexOf('-')
if ($idx -gt 0) {
$segments = $verStr.SubString($idx+1).Split('.')
if ($segments.Count -ge 5) {
if ($segments.Count -gt 5) {
throw "max. 5 segments"
}
# Add all 5 segments to the object
# If the segment is a number, it is converted to an integer
# If the segment is a string, it cannot be -ge 'zzz' (would be sorted wrongly)
0..($segments.Count-1) | ForEach-Object {
$result = 0
if ([int]::TryParse($segments[$_], [ref] $result)) {
Expand All @@ -364,6 +425,7 @@ function SemVerStrToSemVerObj {
}
}
}
# Check that the object can be converted back to the original string
$newStr = SemVerObjToSemVerStr -semVerObj $obj
if ($newStr -cne $semVerStr) {
throw "Not equal"
Expand Down Expand Up @@ -397,8 +459,7 @@ function GetReleases {
$sortedReleases
}
catch {
Write-Host -ForegroundColor red "Some of the release tags cannot be recognized as a semantic version string (https://semver.org)"
Write-Host -ForegroundColor red "Using default GitHub sorting for releases"
Write-Host "::Warning::Some of the release tags cannot be recognized as a semantic version string (https://semver.org). Using default GitHub sorting for releases, which will not work for release branches"
$releases
}
}
Expand All @@ -407,6 +468,35 @@ function GetReleases {
}
}

function GetLatestRelease {
Param(
[string] $token,
[string] $api_url = $ENV:GITHUB_API_URL,
[string] $repository = $ENV:GITHUB_REPOSITORY,
[string] $ref = $ENV:GITHUB_REFNAME
)

Write-Host "Getting the latest release from $api_url/repos/$repository/releases/latest - branch $ref"
# Get all releases from GitHub, sorted by SemVer tag
# If any release tag is not a valid SemVer tag, use default GitHub sorting and issue a warning
# Default github sorting will return the latest historically created release as the latest release - not the highest version
$releases = GetReleases -token $token -api_url $api_url -repository $repository

# Get Latest release
$latestRelease = $releases | Where-Object { -not ($_.prerelease -or $_.draft) } | Select-Object -First 1
$releaseBranchPrefix = 'release/'
if ($ref -like "$releaseBranchPrefix*") {
# If release branch, get the latest release from that the release branch
# This is given by the latest release with the same major.minor as the release branch
$semVerObj = SemVerStrToSemVerObj -semVerStr $ref.SubString($releaseBranchPrefix.Length) -allowMajorMinorOnly
$latestRelease = $releases | Where-Object {
$releaseSemVerObj = SemVerStrToSemVerObj -semVerStr $_.tag_name
$semVerObj.Major -eq $releaseSemVerObj.Major -and $semVerObj.Minor -eq $releaseSemVerObj.Minor
} | Select-Object -First 1
}
$latestRelease
}

function GetHeader {
param (
[string] $token,
Expand Down Expand Up @@ -442,22 +532,6 @@ function GetReleaseNotes {
InvokeWebRequest -Headers (GetHeader -token $token) -Method POST -Body ($postParams | ConvertTo-Json) -Uri "$api_url/repos/$repository/releases/generate-notes"
}

function GetLatestRelease {
Param(
[string] $token,
[string] $api_url = $ENV:GITHUB_API_URL,
[string] $repository = $ENV:GITHUB_REPOSITORY
)

Write-Host "Getting the latest release from $api_url/repos/$repository/releases/latest"
try {
InvokeWebRequest -Headers (GetHeader -token $token) -Uri "$api_url/repos/$repository/releases/latest" -ignoreErrors | ConvertFrom-Json
}
catch {
return $null
}
}

function DownloadRelease {
Param(
[string] $token,
Expand Down
11 changes: 2 additions & 9 deletions Actions/RunPipeline/RunPipeline.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,9 @@ try {
else {
Write-Host "::group::Locating previous release"
try {
$releasesJson = GetReleases -token $token -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY
if ($env:GITHUB_REF_NAME -like 'release/*') {
# For CI/CD in a release branch use that release as previous build
$latestRelease = $releasesJson | Where-Object { $_.tag_name -eq "$env:GITHUB_REF_NAME".SubString(8) } | Select-Object -First 1
}
else {
$latestRelease = $releasesJson | Where-Object { -not ($_.prerelease -or $_.draft) } | Select-Object -First 1
}
$latestRelease = GetLatestRelease -token $token -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY -ref $ENV:GITHUB_REF_NAME
if ($latestRelease) {
Write-Host "Using $($latestRelease.name) as previous release"
Write-Host "Using $($latestRelease.name) (tag $($latestRelease.tag_name)) as previous release"
$artifactsFolder = Join-Path $baseFolder "artifacts"
New-Item $artifactsFolder -ItemType Directory | Out-Null
DownloadRelease -token $token -projects $project -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY -release $latestRelease -path $artifactsFolder -mask "Apps"
Expand Down
26 changes: 22 additions & 4 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,28 @@
Note that when using the preview version of AL-Go for GitHub, you need to Update your AL-Go system files, as soon as possible when told to do so.

### Issues
- Issue #171 create a workspace file when creating a project
- Issue #356 Publish to AppSource fails in multi project repo
- Issue #358 Publish To Environment Action stopped working in v2.3
- Issue #362 Support for EnableTaskScheduler
- Issue [#171](https://github.com/microsoft/AL-Go/issues/171) create a workspace file when creating a project
- Issue [#356](https://github.com/microsoft/AL-Go/issues/356) Publish to AppSource fails in multi project repo
- Issue [#358](https://github.com/microsoft/AL-Go/issues/358) Publish To Environment Action stopped working in v2.3
- Issue [#362](https://github.com/microsoft/AL-Go/issues/362) Support for EnableTaskScheduler
- Issue [#360](https://github.com/microsoft/AL-Go/issues/360) Creating a release and deploying from a release branch
- Issue [#371](https://github.com/microsoft/AL-Go/issues/371) 'No previous release found' for builds on release branches
- Issue [#376](https://github.com/microsoft/AL-Go/issues/376) CICD jobs that are triggered by the pull request trigger run directly to an error if title contains quotes

### Release Branches
**NOTE:** Release Branches are now only named after major.minor if the patch value is 0 in the release tag (which must be semver compatible)

This version contains a number of bug fixes to release branches, to ensure that the recommended branching strategy is fully supported. Bugs fixed includes:
- Release branches was named after the full tag (1.0.0), even though subsequent hotfixes released from this branch would be 1.0.x
- Release branches named 1.0 wasn't picked up as a release branch
- Release notes contained the wrong changelog
- The previous release was always set to be the first release from a release branch
- SemVerStr could not have 5 segments after the dash
- Release was created on the right SHA, but the release branch was created on the wrong SHA

Recommended branching strategy:

![Branching Strategy](Scenarios/images/branchingstrategy.png)

### New Settings
New Project setting: EnableTaskScheduler in container executing tests and when setting up local development environment
Expand Down
Binary file added Scenarios/images/branchingstrategy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 3bd828f

Please sign in to comment.