Modules/businessdev.ALbuild.Core/Public/New-BcBuildBranch.ps1
|
function New-BcBuildBranch { <# .SYNOPSIS Commits the working tree to a build/<version> branch and (optionally) pushes it. .DESCRIPTION Creates (or resets) a branch named "<BranchPrefix><Version>" at the current HEAD, stages all changes, commits them when there is something to commit, and pushes the branch to the remote. This is the carrier of the versioned sources produced by a build; the parallel-build lock is handled separately by Invoke-BcBuildVersionStamp. Pushing requires that the checkout step persisted credentials (e.g. Azure DevOps 'persistCredentials: true'). A push that is rejected because the branch already exists with divergent history is reported as a non-terminating conflict (the returned object's Pushed is $false and a warning is logged) rather than thrown, so a caller doing its own concurrency control can react; any other push failure (auth, missing remote) throws. .PARAMETER Version The version that names the branch. .PARAMETER RepositoryRoot The git working tree. Default: the current location. .PARAMETER BranchPrefix Prefix for the branch name. Default 'build/'. .PARAMETER CommitMessage Commit message. Default "Build <Version>". .PARAMETER UserName git author/committer name set locally for the commit. Default 'ALbuild CI'. .PARAMETER UserEmail git author/committer email set locally for the commit. Default 'albuild@365businessdev.com'. .PARAMETER Remote The remote to push to. Default 'origin'. .PARAMETER Force Force-push the branch (overwrites an existing remote branch). Use with care. .PARAMETER NoPush Create and commit the branch locally without pushing (used by the local pipeline runner). .EXAMPLE New-BcBuildBranch -Version '2.3.0.0' .OUTPUTS PSCustomObject: Branch, Committed, Pushed, Conflict. #> [CmdletBinding(SupportsShouldProcess)] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Version, [string] $RepositoryRoot = (Get-Location).Path, [string] $BranchPrefix = 'build/', [string] $CommitMessage, [string] $UserName = 'ALbuild CI', [string] $UserEmail = 'albuild@365businessdev.com', [string] $Remote = 'origin', [switch] $Force, [switch] $NoPush ) if (-not (Test-Path -LiteralPath $RepositoryRoot)) { throw "Repository root '$RepositoryRoot' does not exist." } $branch = "$BranchPrefix$Version" if (-not $CommitMessage) { $CommitMessage = "Build $Version" } if (-not $PSCmdlet.ShouldProcess($branch, 'Create build branch')) { return [PSCustomObject]@{ Branch = $branch; Committed = $false; Pushed = $false; Conflict = $false } } Invoke-BcGit -RepositoryRoot $RepositoryRoot -Arguments @('config', 'user.name', $UserName) | Out-Null Invoke-BcGit -RepositoryRoot $RepositoryRoot -Arguments @('config', 'user.email', $UserEmail) | Out-Null Invoke-BcGit -RepositoryRoot $RepositoryRoot -Arguments @('checkout', '-B', $branch) | Out-Null Invoke-BcGit -RepositoryRoot $RepositoryRoot -Arguments @('add', '-A') | Out-Null # 'diff --cached --quiet' exits 0 when nothing is staged, 1 when there are staged changes. $staged = Invoke-BcGit -RepositoryRoot $RepositoryRoot -Arguments @('diff', '--cached', '--quiet') -AllowFailure $committed = $false if ($staged.ExitCode -ne 0) { Invoke-BcGit -RepositoryRoot $RepositoryRoot -Arguments @('commit', '-m', $CommitMessage) | Out-Null $committed = $true Write-ALbuildLog -Level Information "Committed build sources to '$branch'." } else { Write-ALbuildLog -Level Information "No changes to commit on '$branch'." } if ($NoPush) { Write-ALbuildLog -Level Information "Skipping push of '$branch' (-NoPush)." return [PSCustomObject]@{ Branch = $branch; Committed = $committed; Pushed = $false; Conflict = $false } } $pushArgs = @('push') if ($Force) { $pushArgs += '--force' } $pushArgs += @($Remote, $branch) $push = Invoke-BcGit -RepositoryRoot $RepositoryRoot -Arguments $pushArgs -AllowFailure if ($push.Success) { Write-ALbuildLog -Level Success "Pushed build branch '$branch' to '$Remote'." return [PSCustomObject]@{ Branch = $branch; Committed = $committed; Pushed = $true; Conflict = $false } } if (Test-BcGitPushConflict -StdErr $push.StdErr) { Write-ALbuildLog -Level Warning "Build branch '$branch' already exists on '$Remote' with divergent history; not pushed." return [PSCustomObject]@{ Branch = $branch; Committed = $committed; Pushed = $false; Conflict = $true } } $detail = if ([string]::IsNullOrWhiteSpace($push.StdErr)) { $push.StdOut } else { $push.StdErr } throw "Failed to push build branch '$branch' to '$Remote' (exit $($push.ExitCode)). Ensure the checkout persisted credentials.$([Environment]::NewLine)$($detail.Trim())" } |