Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release Branches #374

Merged
merged 20 commits into from
Jan 25, 2023
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