Public/Update-CpmfUipsPackProjectVersion.ps1

function Update-CpmfUipsPackProjectVersion {
<#
.SYNOPSIS
    Reads projectVersion from a UiPath project.json, increments it, writes it back,
    and returns the new version string.
 
.DESCRIPTION
    Version bump rules:
      - Prerelease suffix with numeric tail (1.2.3-alpha.4) → alpha.5
      - Prerelease suffix without numeric (1.2.3-alpha) → alpha.1
      - Build metadata with numeric tail (1.2.3+build.4) → build.5
      - Plain release (1.2.3) → 1.3.0 (minor bump)
 
    With -NoBump, the file is not modified; the current version is returned.
 
.PARAMETER ProjectJson
    Path to the UiPath project.json file.
 
.PARAMETER NoBump
    Return the current version without writing any changes.
 
.PARAMETER ProjectVersion
    Write this exact version string to project.json instead of computing an auto-bump.
    Mutually exclusive with -NoBump.
 
.OUTPUTS
    [string] The new (or current, if -NoBump) version string.
#>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([string])]
    param(
        [Parameter(Mandatory)]
        [string]$ProjectJson,

        [switch]$NoBump,

        [string]$ProjectVersion
    )

    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'

    $ProjectJson = (Resolve-Path $ProjectJson).Path
    $raw = Get-Content $ProjectJson -Raw

    if ($raw -notmatch '"projectVersion"\s*:\s*"([^"]*)"') {
        throw "projectVersion key not found in $ProjectJson — is this a valid UiPath project.json?"
    }
    $current = $Matches[1]

    if ($NoBump) {
        Write-Output $current
        return
    }

    $newVersion = if ($PSBoundParameters.ContainsKey('ProjectVersion') -and $ProjectVersion -ne '') {
        $ProjectVersion
    } elseif ($current -match '^(\d+\.\d+\.\d+)-(.+)$') {
        $base = $Matches[1]; $pre = $Matches[2]
        $bumped = if ($pre -match '^(.+\.)(\d+)$') { "$($Matches[1])$([int]$Matches[2] + 1)" } else { "$pre.1" }
        "$base-$bumped"
    } elseif ($current -match '^(\d+\.\d+\.\d+)\+(.+)$') {
        $base = $Matches[1]; $build = $Matches[2]
        $bumped = if ($build -match '^(.+\.)(\d+)$') { "$($Matches[1])$([int]$Matches[2] + 1)" } else { "$build.1" }
        "$base+$bumped"
    } else {
        $parts = $current -split '\.'
        if ($parts.Count -ne 3) { throw "Cannot parse version '$current' — expected major.minor.patch" }
        "$($parts[0]).$([int]$parts[1] + 1).0"
    }

    $updated = $raw -replace '("projectVersion"\s*:\s*")[^"]*(")', "`${1}$newVersion`${2}"
    if ($PSCmdlet.ShouldProcess($ProjectJson, "Write projectVersion $current → $newVersion")) {
        [System.IO.File]::WriteAllText($ProjectJson, $updated, (New-Object System.Text.UTF8Encoding $false))
    }

    Write-Output $newVersion
}