[CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$BaseBranchUrl, [Parameter(Mandatory = $false)] [string]$BranchName, [Parameter(Mandatory = $false)] [string]$Ticket, [Parameter(Mandatory = $false)] [string]$Description, [Parameter(Mandatory = $false)] [string]$AuthorInitials, [Parameter(Mandatory = $false)] [string]$CommitMessage, [Parameter(Mandatory = $false)] [string]$CheckoutPath, [switch]$Force, [switch]$WhatIfOnly ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" function Assert-SvnCli { if (-not (Get-Command svn -ErrorAction SilentlyContinue)) { throw "Le client svn n'est pas disponible dans le PATH." } } function Normalize-Slug { param([string]$Value) if ([string]::IsNullOrWhiteSpace($Value)) { return "modif" } $normalized = $Value.ToLowerInvariant() $normalized = $normalized -replace "[^a-z0-9]+", "-" $normalized = $normalized.Trim("-") if ([string]::IsNullOrWhiteSpace($normalized)) { return "modif" } return $normalized } function Get-ParentUrl { param([string]$Url) $trimmed = $Url.TrimEnd("/") $lastSlashIndex = $trimmed.LastIndexOf("/") if ($lastSlashIndex -lt 0) { throw "Impossible de determiner le parent de l'URL: $Url" } return $trimmed.Substring(0, $lastSlashIndex) } function Test-BranchExists { param([string]$Url) & svn info "$Url" *> $null return ($LASTEXITCODE -eq 0) } function New-DefaultBranchName { param( [string]$Ticket, [string]$Description, [string]$AuthorInitials ) $datePart = (Get-Date).ToString("yyyyMMdd") $ticketPart = if ([string]::IsNullOrWhiteSpace($Ticket)) { "NO-TICKET" } else { $Ticket.Trim().ToUpperInvariant() } $authorPart = if ([string]::IsNullOrWhiteSpace($AuthorInitials)) { "XX" } else { $AuthorInitials.Trim().ToUpperInvariant() } $slugPart = Normalize-Slug -Value $Description return "dev_${ticketPart}_${authorPart}_${slugPart}_${datePart}" } function Validate-BranchName { param([string]$Name) $regex = "^dev_[A-Z0-9-]+_[A-Z]{2,5}_[a-z0-9-]+_[0-9]{8}$" if ($Name -notmatch $regex) { throw @" Nom de branche invalide: $Name Pattern attendu: dev____ Exemple: dev_SPRF-3124_HBK_fix-journalisation-404_20260319 "@ } } function New-DefaultCommitMessage { param( [string]$Ticket, [string]$Description, [string]$BranchName ) $ticketPart = if ([string]::IsNullOrWhiteSpace($Ticket)) { "NO-TICKET" } else { $Ticket.Trim().ToUpperInvariant() } $descriptionPart = if ([string]::IsNullOrWhiteSpace($Description)) { "Correctifs" } else { $Description.Trim() } return "$ticketPart - $descriptionPart | Branche: $BranchName" } Assert-SvnCli if ([string]::IsNullOrWhiteSpace($BranchName)) { $BranchName = New-DefaultBranchName -Ticket $Ticket -Description $Description -AuthorInitials $AuthorInitials } Validate-BranchName -Name $BranchName $baseUrl = $BaseBranchUrl.TrimEnd("/") $parentUrl = Get-ParentUrl -Url $baseUrl $newBranchUrl = "$parentUrl/$BranchName" if ([string]::IsNullOrWhiteSpace($CommitMessage)) { $CommitMessage = New-DefaultCommitMessage -Ticket $Ticket -Description $Description -BranchName $BranchName } Write-Host "Base branch URL : $baseUrl" -ForegroundColor Cyan Write-Host "New branch name : $BranchName" -ForegroundColor Cyan Write-Host "New branch URL : $newBranchUrl" -ForegroundColor Cyan Write-Host "Create message : $CommitMessage" -ForegroundColor Cyan if (-not [string]::IsNullOrWhiteSpace($CheckoutPath)) { Write-Host "Checkout path : $CheckoutPath" -ForegroundColor Cyan } if ((Test-BranchExists -Url $newBranchUrl) -and -not $Force) { throw "La branche existe deja: $newBranchUrl. Utilisez -Force pour continuer." } if ($WhatIfOnly) { Write-Host "Mode simulation: aucune commande svn copy/checkout executee." -ForegroundColor Yellow return } if (Test-BranchExists -Url $newBranchUrl) { Write-Host "La branche existe deja et -Force est actif. Aucune creation effectuee." -ForegroundColor Yellow } else { Write-Host "Creation de la branche..." -ForegroundColor Green & svn copy "$baseUrl" "$newBranchUrl" -m "$CommitMessage" if ($LASTEXITCODE -ne 0) { throw "Echec de creation de branche SVN." } } if (-not [string]::IsNullOrWhiteSpace($CheckoutPath)) { if (Test-Path -LiteralPath $CheckoutPath) { if (-not $Force) { throw "Le repertoire de checkout existe deja: $CheckoutPath. Utilisez -Force pour l'autoriser." } Write-Host "Le repertoire existe deja, checkout ignore en mode -Force." -ForegroundColor Yellow } else { Write-Host "Checkout de la nouvelle branche..." -ForegroundColor Green & svn checkout "$newBranchUrl" "$CheckoutPath" if ($LASTEXITCODE -ne 0) { throw "Echec du checkout SVN." } } } Write-Host "Termine." -ForegroundColor Green Write-Host "Message de commit suggere pour les changements de code:" -ForegroundColor Cyan Write-Host ("{0} - Correctifs journalisation (404 toleres + fallback reponse vide)" -f ($(if ([string]::IsNullOrWhiteSpace($Ticket)) { "NO-TICKET" } else { $Ticket.Trim().ToUpperInvariant() }))) -ForegroundColor Gray