| [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_<TICKET>_<INITIALS>_<DESCRIPTION-KEBAB-CASE>_<YYYYMMDD> |
| 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 |
|
|