Skip to content

Commit

Permalink
Improve IncrementVersionNumber action (microsoft#910)
Browse files Browse the repository at this point in the history
Fixes microsoft#889 : `appFolders` with wild characters are not resolved when
reading the app.json files.
Also fixes issue that the `version` property in `dependencies` array in
the app.json is not changed.

- [x] Release notes
- [x] More tests
  • Loading branch information
mazhelez committed Feb 12, 2024
1 parent 5000d6c commit 8c97a30
Show file tree
Hide file tree
Showing 6 changed files with 486 additions and 80 deletions.
114 changes: 39 additions & 75 deletions Actions/IncrementVersionNumber/IncrementVersionNumber.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[string] $parentTelemetryScopeJson = '7b7d',
[Parameter(HelpMessage = "List of project names if the repository is setup for multiple projects (* for all projects)", Mandatory = $false)]
[string] $projects = '*',
[Parameter(HelpMessage = "Updated Version Number. Use Major.Minor for absolute change, use +Major.Minor for incremental change.", Mandatory = $true)]
[Parameter(HelpMessage = "The version to update to. Use Major.Minor for absolute change, use +1 to bump to the next major version, use +0.1 to bump to the next minor version", Mandatory = $true)]
[string] $versionNumber,
[Parameter(HelpMessage = "Set the branch to update", Mandatory = $false)]
[string] $updateBranch,
Expand All @@ -19,92 +19,56 @@ $telemetryScope = $null

try {
. (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve)
Import-Module (Join-Path -path $PSScriptRoot -ChildPath "IncrementVersionNumber.psm1" -Resolve)

$serverUrl, $branch = CloneIntoNewFolder -actor $actor -token $token -updateBranch $updateBranch -DirectCommit $directCommit -newBranchPrefix 'increment-version-number'
$baseFolder = (Get-Location).path
DownloadAndImportBcContainerHelper -baseFolder $baseFolder

import-module (Join-Path -path $PSScriptRoot -ChildPath "..\TelemetryHelper.psm1" -Resolve)
Import-Module (Join-Path -path $PSScriptRoot -ChildPath "..\TelemetryHelper.psm1" -Resolve)
$telemetryScope = CreateScope -eventId 'DO0076' -parentTelemetryScopeJson $parentTelemetryScopeJson

$addToVersionNumber = "$versionNumber".StartsWith('+')
if ($addToVersionNumber) {
$versionNumber = $versionNumber.Substring(1)
}
try {
$newVersion = [System.Version]"$($versionNumber).0.0"
}
catch {
throw "Version number ($versionNumber) is malformed. A version number must be structured as <Major>.<Minor> or +<Major>.<Minor>"
}

$settings = $env:Settings | ConvertFrom-Json

# Ensure the repoVersion setting exists in the repository settings. Defaults to 1.0 if it doesn't exist.
Set-VersionInSettingsFile -settingsFilePath (Join-Path $baseFolder $RepoSettingsFile) -settingName 'repoVersion' -newValue $settings.repoVersion -Force # $RepoSettingsFile is defined in AL-Go-Helper.ps1

# Change repoVersion in repository settings
Set-VersionInSettingsFile -settingsFilePath (Join-Path $baseFolder $RepoSettingsFile) -settingName 'repoVersion' -newValue $versionNumber

$projectList = @(GetProjectsFromRepository -baseFolder $baseFolder -projectsFromSettings $settings.projects -selectProjects $projects)

$allAppFolders = @()
foreach($project in $projectList) {
try {
Write-Host "Reading settings from $project\$ALGoSettingsFile"
$settingsJson = Get-Content "$project\$ALGoSettingsFile" -Encoding UTF8 | ConvertFrom-Json
if ($settingsJson.PSObject.Properties.Name -eq "repoVersion") {
$oldVersion = [System.Version]"$($settingsJson.repoVersion).0.0"
if ((!$addToVersionNumber) -and $newVersion -le $oldVersion) {
throw "The new version number ($($newVersion.Major).$($newVersion.Minor)) must be larger than the old version number ($($oldVersion.Major).$($oldVersion.Minor))"
}
$repoVersion = $newVersion
if ($addToVersionNumber) {
$repoVersion = [System.Version]"$($newVersion.Major+$oldVersion.Major).$($newVersion.Minor+$oldVersion.Minor).0.0"
}
$settingsJson.repoVersion = "$($repoVersion.Major).$($repoVersion.Minor)"
}
else {
$repoVersion = $newVersion
if ($addToVersionNumber) {
$repoVersion = [System.Version]"$($newVersion.Major+1).$($newVersion.Minor).0.0"
}
Add-Member -InputObject $settingsJson -NotePropertyName "repoVersion" -NotePropertyValue "$($repoVersion.Major).$($repoVersion.Minor)" | Out-Null
}
$useRepoVersion = (($settingsJson.PSObject.Properties.Name -eq "versioningStrategy") -and (($settingsJson.versioningStrategy -band 16) -eq 16))
$settingsJson
$settingsJson | Set-JsonContentLF -path "$project\$ALGoSettingsFile"
}
catch {
throw "Settings file $project\$ALGoSettingsFile is malformed.$([environment]::Newline) $($_.Exception.Message)."
}

$folders = @('appFolders', 'testFolders' | ForEach-Object { if ($SettingsJson.PSObject.Properties.Name -eq $_) { $settingsJson."$_" } })
if (-not ($folders)) {
$folders = Get-ChildItem -Path $project | Where-Object { $_.PSIsContainer -and (Test-Path (Join-Path $_.FullName 'app.json')) } | ForEach-Object { $_.Name }
}
$folders | ForEach-Object {
Write-Host "Modifying app.json in folder $project\$_"
$appJsonFile = Join-Path "$project\$_" "app.json"
if (Test-Path $appJsonFile) {
try {
$appJson = Get-Content $appJsonFile -Encoding UTF8 | ConvertFrom-Json
$oldVersion = [System.Version]$appJson.Version
if ($useRepoVersion) {
$appVersion = $repoVersion
}
elseif ($addToVersionNumber) {
$appVersion = [System.Version]"$($newVersion.Major+$oldVersion.Major).$($newVersion.Minor+$oldVersion.Minor).0.0"
}
else {
$appVersion = $newVersion
}
$appJson.Version = "$appVersion"
$appJson | Set-JsonContentLF -path $appJsonFile
}
catch {
throw "Application manifest file($appJsonFile) is malformed."
}
}
}
}
if ($addToVersionNumber) {
CommitFromNewFolder -serverUrl $serverUrl -commitMessage "Increment Version number by $($newVersion.Major).$($newVersion.Minor)" -branch $branch | Out-Null
$projectPath = Join-Path $baseFolder $project

# Set repoVersion in project settings (if it exists)
$projectSettingsPath = Join-Path $projectPath $ALGoSettingsFile # $ALGoSettingsFile is defined in AL-Go-Helper.ps1
Set-VersionInSettingsFile -settingsFilePath $projectSettingsPath -settingName 'repoVersion' -newValue $versionNumber

# Resolve project folders to get all app folders that contain an app.json file
$projectSettings = ReadSettings -baseFolder $baseFolder -project $project
ResolveProjectFolders -baseFolder $baseFolder -project $project -projectSettings ([ref] $projectSettings)

# Set version in app manifests (app.json files)
Set-VersionInAppManifests -projectPath $projectPath -projectSettings $projectSettings -newValue $versionNumber

# Collect all project's app folders
$allAppFolders += $projectSettings.appFolders | ForEach-Object { Join-Path $projectPath $_ -Resolve }
$allAppFolders += $projectSettings.testFolders | ForEach-Object { Join-Path $projectPath $_ -Resolve }
$allAppFolders += $projectSettings.bcptTestFolders | ForEach-Object { Join-Path $projectPath $_ -Resolve }
}
else {
CommitFromNewFolder -serverUrl $serverUrl -commitMessage "New Version number $($newVersion.Major).$($newVersion.Minor)" -branch $branch | Out-Null

# Set dependencies in app manifests
Set-DependenciesVersionInAppManifests -appFolders $allAppFolders

$commitMessage = "New Version number $versionNumber"
if ($versionNumber.StartsWith('+')) {
$commitMessage = "Incremented Version number by $versionNumber"
}

CommitFromNewFolder -serverUrl $serverUrl -commitMessage $commitMessage -branch $branch | Out-Null

TrackTrace -telemetryScope $telemetryScope
}
catch {
Expand Down
200 changes: 200 additions & 0 deletions Actions/IncrementVersionNumber/IncrementVersionNumber.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<#
.Synopsis
Changes a version setting value in a settings file.
.Description
Changes a version setting value in a settings file.
If the setting does not exist in the settings file, the function does nothing, unless the Force parameter is specified.
.Parameter settingsFilePath
Path to a JSON file containing the settings.
.Parameter settingName
Name of the setting to change. The setting must be a version number.
.Parameter newValue
New value of the setting. Allowed values are: +1 (increment major version number), +0.1 (increment minor version number), or a version number in the format Major.Minor (e.g. 1.0 or 1.2
.Parameter Force
If specified, the function will create the setting if it does not exist in the settings file.
#>
function Set-VersionInSettingsFile {
param(
[Parameter(Mandatory = $true)]
[string] $settingsFilePath,
[Parameter(Mandatory = $true)]
[string] $settingName,
[Parameter(Mandatory = $true)]
[string] $newValue,
[switch] $Force
)

#region Validate parameters
if (-not (Test-Path $settingsFilePath)) {
throw "Settings file ($settingsFilePath) not found."
}

Write-Host "Reading settings from $settingsFilePath"
try {
$settingsJson = Get-Content $settingsFilePath -Encoding UTF8 -Raw | ConvertFrom-Json
}
catch {
throw "Settings file ($settingsFilePath) is malformed: $_"
}

$settingExists = [bool] ($settingsJson.PSObject.Properties.Name -eq $settingName)
if ((-not $settingExists) -and (-not $Force)) {
Write-Host "Setting $settingName not found in $settingsFilePath"
return
}

# Add the setting if it does not exist
if (-not $settingExists) {
$settingsJson | Add-Member -MemberType NoteProperty -Name $settingName -Value $null
}

$oldValue = [System.Version] $settingsJson.$settingName
# Validate new version value
if ($newValue.StartsWith('+')) {
# Handle incremental version number

$allowedIncrementalVersionNumbers = @('+1', '+0.1')
if (-not $allowedIncrementalVersionNumbers.Contains($newValue)) {
throw "Incremental version number $newValue is not allowed. Allowed incremental version numbers are: $($allowedIncrementalVersionNumbers -join ', ')"
}

# Defensive check. Should never happen.
if($null -eq $oldValue) {
throw "The setting $settingName does not exist in the settings file. It must exist to be able to increment the version number."
}
}
else {
# Handle absolute version number

$versionNumberFormat = '^\d+\.\d+$' # Major.Minor
if (-not ($newValue -match $versionNumberFormat)) {
throw "Version number $newValue is not in the correct format. The version number must be in the format Major.Minor (e.g. 1.0 or 1.2)"
}
}
#endregion

$versionNumbers = @() # an array to hold the version numbers: major, minor, build, revision

switch($newValue) {
'+1' {
# Increment major version number
$versionNumbers += $oldValue.Major + 1
$versionNumbers += 0
}
'+0.1' {
# Increment minor version number
$versionNumbers += $oldValue.Major
$versionNumbers += $oldValue.Minor + 1

}
default {
# Absolute version number
$versionNumbers += $newValue.Split('.')
}
}

# Include build and revision numbers if they exist in the old version number
if ($oldValue -and ($oldValue.Build -ne -1)) {
$versionNumbers += $oldValue.Build
if ($oldValue.Revision -ne -1) {
$versionNumbers += $oldValue.Revision
}
}

# Construct the new version number. Cast to System.Version to validate if the version number is valid.
$newValue = [System.Version] "$($versionNumbers -join '.')"

if($newValue -eq $oldValue) {
Write-Host "The setting $settingName is already set to $newValue in $settingsFilePath"
return
}

if($null -eq $oldValue) {
Write-Host "Setting setting $settingName to $newValue in $settingsFilePath"
}
else {
Write-Host "Changing $settingName from $oldValue to $newValue in $settingsFilePath"
}

$settingsJson.$settingName = $newValue.ToString()
$settingsJson | Set-JsonContentLF -Path $settingsFilePath
}

<#
.Synopsis
Changes the version number of a project.
.Description
Changes the version number of a project.
The version number is changed in the project settings file (value for 'repoVersion') and in the app.json files of all apps in the project, as well as all references to the apps in the dependencies of the app.json files.
.Parameter baseFolder
Base folder of the repository.
.Parameter project
Name of the project (relative to the base folder).
.Parameter newValue
New version number. If the version number starts with a +, the new version number will be added to the old version number. Else the new version number will replace the old version number.
#>
function Set-VersionInAppManifests($projectPath, $projectSettings, $newValue) {

# Check if the project uses repoVersion versioning strategy
$useRepoVersion = (($projectSettings.PSObject.Properties.Name -eq "versioningStrategy") -and (($projectSettings.versioningStrategy -band 16) -eq 16))
if ($useRepoVersion) {
$newValue = $projectSettings.repoVersion
}

$allAppFolders = @($projectSettings.appFolders) + @($projectSettings.testFolders) + @($projectSettings.bcptTestFolders)
# Set version in app.json files
$allAppFolders | ForEach-Object {
$appFolder = Join-Path $projectPath $_
$appJson = Join-Path $appFolder "app.json"

Set-VersionInSettingsFile -settingsFilePath $appJson -settingName 'version' -newValue $newValue
}
}

<#
.Synopsis
Changes the version number of dependencies in app.json files.
.Description
Changes the version number of dependencies in app.json files.
The version number of the dependencies is changed to the version number of the app that the dependency refers to. If the app is not found, the version number of the dependency is not changed.
.Parameter appFolders
Array of paths to the app folders. Each app folder must contain an app.json file. The apps are used to get the version number of the dependencies.
#>
function Set-DependenciesVersionInAppManifests {
param(
[Parameter(Mandatory = $true)]
[string[]] $appFolders
)

# Get all apps info: app ID and app version
$appsInfos = @($appFolders | ForEach-Object {
$appJson = Join-Path $_ "app.json"
$app = Get-Content -Path $appJson -Encoding UTF8 -Raw | ConvertFrom-Json
return [PSCustomObject]@{
Id = $app.id
Version = $app.version
}
})

# Update dependencies in app.json files
$appFolders | ForEach-Object {
$appJsonPath = Join-Path $_ "app.json"

$appJson = Get-Content -Path $appJsonPath -Encoding UTF8 -Raw | ConvertFrom-Json

$dependencies = $appJson.dependencies

$dependencies | ForEach-Object {
$dependency = $_
$appInfo = $appsInfos | Where-Object { $_.Id -eq $dependency.id }
if ($appInfo) {
Write-Host "Updating dependency app $($dependency.id) in $appJsonPath from $($dependency.version) to $($appInfo.Version)"
$dependency.version = $appInfo.Version
}
}

$appJson | Set-JsonContentLF -Path $appJsonPath
}
}

Export-ModuleMember -Function Set-VersionInSettingsFile, Set-VersionInAppManifests, Set-DependenciesVersionInAppManifests
2 changes: 1 addition & 1 deletion Actions/IncrementVersionNumber/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Increment version number in AL-Go repository
| token | | The GitHub token running the action | github.token |
| parentTelemetryScopeJson | | Specifies the parent telemetry scope for the telemetry signal | {} |
| projects | | List of project names if the repository is setup for multiple projects (* for all projects) | * |
| versionNumber | Yes | Updated Version Number. Use Major.Minor for absolute change, use +Major.Minor for incremental change | |
| versionNumber | Yes | The version to update to. Use Major.Minor for absolute change, use +1 to bump to the next major version, use +0.1 to bump to the next minor version | |
| updateBranch | | Which branch should the app be added to | github.ref_name |
| directCommit | | true if the action should create a direct commit against the branch or false to create a Pull Request | false |

Expand Down
2 changes: 1 addition & 1 deletion Actions/IncrementVersionNumber/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ inputs:
required: false
default: '*'
versionNumber:
description: Updated Version Number. Use Major.Minor for absolute change, use +Major.Minor for incremental change.
description: The version to update to. Use Major.Minor for absolute change, use +1 to bump to the next major version, use +0.1 to bump to the next minor version
required: true
updateBranch:
description: Set the branch to update
Expand Down
7 changes: 4 additions & 3 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ Note that when using the preview version of AL-Go for GitHub, we recommend you U
### Issues
- Support release branches that start with releases/
- Issue 870 Improve Error Handling when CLI is missing
- Issue 889 CreateRelease and IncrementVersionNumber workflow did not handle wild characters in `appFolders`, `testFolders` or `bcptTestFolders` settings.

### Build modes
AL-Go ships with Default, Translated and Clean mode out of the box. Now you can also define custom build modes in addition to the ones shipped with AL-Go. This allows you to define your own build modes, which can be used to build your apps in different ways. By default, a custom build mode will build the apps similarly to the Default mode but this behavior can be overridden in e.g. script overrides in your repository.
### Build modes
AL-Go ships with Default, Translated and Clean mode out of the box. Now you can also define custom build modes in addition to the ones shipped with AL-Go. This allows you to define your own build modes, which can be used to build your apps in different ways. By default, a custom build mode will build the apps similarly to the Default mode but this behavior can be overridden in e.g. script overrides in your repository.

## v4.1

Expand Down Expand Up @@ -45,7 +46,7 @@ If false, the templateSha repository setting is used to download specific AL-Go
- **footer** = Footer for the documentation site. (Default: Made with...)
- **defaultIndexMD** = Markdown for the landing page of the documentation site. (Default: Reference documentation...)
- **defaultReleaseMD** = Markdown for the landing page of the release sites. (Default: Release reference documentation...)
- *Note that in header, footer, defaultIndexMD and defaultReleaseMD you can use the following placeholders: {REPOSITORY}, {VERSION}, {INDEXTEMPLATERELATIVEPATH}, {RELEASENOTES}*
- *Note that in header, footer, defaultIndexMD and defaultReleaseMD you can use the following placeholders: {REPOSITORY}, {VERSION}, {INDEXTEMPLATERELATIVEPATH}, {RELEASENOTES}*

### New Workflows
- **Deploy Reference Documentation** is a workflow, which you can invoke manually or on a schedule to generate and deploy reference documentation using the aldoc tool, using the ALDoc setting properties described above.
Expand Down
Loading

0 comments on commit 8c97a30

Please sign in to comment.