diff --git a/roa_sync.ps1 b/roa_sync.ps1 index cbd2318..a36f5ca 100644 --- a/roa_sync.ps1 +++ b/roa_sync.ps1 @@ -1,45 +1,12 @@ <# .SYNOPSIS - Sincronizare de inceput de sesiune pentru un proiect ROA (flux SVN + git text FoxBin2Prg). + STUB de compatibilitate: roa_sync.ps1 s-a MUTAT in COMUN\scripts\roa_sync.ps1 + (se distribuie automat prin svn update, ca restul COMUN). .DESCRIPTION - Pasii: - 1. svn update pe ProjectRoot (include externalul COMUN\). Esec / conflicte -> stop, exit nenul. - 2. git_sync.ps1 -ProjectRoot (improspateaza textele .??2, inclusiv COMUN). - Esec (exit nenul) -> avertizare, fara commit-uri de sync, exit nenul. - 3. Repo proiect (ProjectRoot\.git): pe main comite "sync SVN r" daca sunt schimbari, - apoi reconciliaza cu origin si face push conditionat (vezi mai jos). - 4. La fel repo COMUN (ProjectRoot\COMUN\.git), cu revizia din svn info pe folderul COMUN. - 5. Inchide branch-urile claude/* terminate (git diff main..branch gol) in ambele repo-uri. - 6. Sumar final (commit / reconciliere / push per repo + avertismente). - - Reconcilierea cu origin (pasii 3-4, DUPA commit-ul local de sync - commit-ul intai face - tree-ul curat si aduce sub urmarire fisierele noi, deci nu mai apar blocajele clasice de - pull peste modificari necomise / fisiere netracked): - - git fetch origin; fara remote origin sau fetch esuat (offline) -> avertisment si - comportamentul vechi (doar commit local), exit 0. - - doar in urma fata de origin/main -> git merge --ff-only origin/main. - - divergenta -> git rebase origin/main. Commit-urile de sync al caror continut e deja - identic pe origin (alta masina a rulat acelasi svn update + sync + push inaintea - noastra) devin goale la rebase si sunt aruncate automat - NU e conflict si nu cere - interventie manuala. - - conflict REAL la rebase -> git rebase --abort, avertisment, exit nenul la final. - - push origin main DOAR daca toate commit-urile ahead de origin/main sunt commit-uri de - sync ("sync SVN[ r]" - continut oglindit din SVN, sursa de adevar). Orice commit - non-sync nepushed blocheaza push-ul automat (avertisment; push manual dupa review). - - push respins (push simultan de pe alta masina) -> reia fetch + reconciliere + push, - maxim 3 incercari, apoi avertisment (se reconciliaza la urmatoarea rulare). - - Exit: nenul la esec svn/git_sync sau conflict real cu origin; avertismentele (offline, - push sarit din cauza commit-urilor non-sync, push esuat) lasa exit 0 si apar in sumar. - -.PARAMETER ProjectRoot - Radacina proiectului. Implicit: directorul curent, daca are .git si un .pjx. - -.PARAMETER GitOnly - Sare peste pasii SVN (1) si regenerarea textelor (2): doar commit + reconciliere + push + - inchidere branch-uri. Pentru reconciliere rapida cu origin sau pentru teste - (test_roa_sync.ps1) - nu cere working copy SVN si nici FoxBin2Prg. + Deleaga la copia proiectului: \COMUN\scripts\roa_sync.ps1. Daca lipseste + (working copy neactualizat inca), face intai svn update pe proiect ca sa o aduca. + Actualizeaza lansatoarele (roa_sync.bat) sa cheme direct COMUN\scripts\roa_sync.ps1. #> [CmdletBinding()] param( @@ -49,7 +16,6 @@ param( $ErrorActionPreference = 'Stop' -# --- deduce ProjectRoot din directorul curent daca nu e dat --- if (-not $ProjectRoot) { $cwd = (Get-Location).Path $hasGit = Test-Path -LiteralPath (Join-Path $cwd '.git') @@ -61,272 +27,19 @@ if (-not $ProjectRoot) { exit 1 } } -if (-not (Test-Path -LiteralPath $ProjectRoot -PathType Container)) { - Write-Host "EROARE: ProjectRoot nu exista: $ProjectRoot" - exit 1 -} -$ProjectRoot = (Get-Item -LiteralPath $ProjectRoot).FullName -$comunRoot = Join-Path $ProjectRoot 'COMUN' -$gitSync = Join-Path $PSScriptRoot 'git_sync.ps1' -Write-Host "=== roa_sync: ProjectRoot=$ProjectRoot$(if($GitOnly){' (-GitOnly)'}) ===" - -# --- helper: revizia SVN a unui folder --- -function Get-SvnRev([string]$path) { - # EAP local Continue: sub Stop, redirectarea 2>$null a stderr-ului nativ arunca in PS 5.1 - $ErrorActionPreference = 'Continue' - $rev = (& svn info --show-item revision $path 2>$null | Out-String).Trim() - if ($LASTEXITCODE -ne 0 -or -not $rev) { return '' } - return $rev -} - -# =========================== 1. svn update =========================== -$rev = '' -Write-Host '' -if ($GitOnly) { - Write-Host "--- 1. svn update: sarit (-GitOnly) ---" -} else { - Write-Host "--- 1. svn update ---" - $svnOut = & svn update $ProjectRoot - $svnExit = $LASTEXITCODE - $svnOut | ForEach-Object { Write-Host " $_" } - if ($svnExit -ne 0) { - Write-Host "EROARE: svn update a esuat (exit $svnExit). Ma opresc." - exit 1 - } - # svn poate iesi 0 dar raporta conflicte in sumar - if ($svnOut | Where-Object { $_ -match 'Summary of conflicts|conflict' }) { - Write-Host "EROARE: svn update raporteaza conflicte. Rezolva-le manual, apoi reia. Ma opresc." - exit 1 - } - $rev = Get-SvnRev $ProjectRoot - Write-Host " Revizie SVN ProjectRoot: $(if($rev){$rev}else{'necunoscuta'})" -} - -# =========================== 2. git_sync =========================== -Write-Host '' -if ($GitOnly) { - Write-Host "--- 2. git_sync: sarit (-GitOnly) ---" -} else { - Write-Host "--- 2. git_sync (texte .??2) ---" - if (-not (Test-Path -LiteralPath $gitSync)) { - Write-Host "EROARE: nu gasesc git_sync.ps1 la $gitSync. Ma opresc." - exit 1 - } - & powershell -ExecutionPolicy Bypass -NoProfile -File $gitSync -ProjectRoot $ProjectRoot - $syncExit = $LASTEXITCODE - if ($syncExit -ne 0) { - Write-Host '' - Write-Host "AVERTISMENT: git_sync a raportat esecuri (exit $syncExit). NU fac commit-uri de sync. Ma opresc." +$target = Join-Path $ProjectRoot 'COMUN\scripts\roa_sync.ps1' +if (-not (Test-Path -LiteralPath $target)) { + Write-Host "roa_sync.ps1 s-a mutat in COMUN\scripts si lipseste inca din working copy - rulez svn update ca sa il aduc." + & svn update $ProjectRoot + if (-not (Test-Path -LiteralPath $target)) { + Write-Host "EROARE: $target lipseste si dupa svn update. Verifica externalul COMUN." exit 1 } } -# =========================== 3-4. commit sync + reconciliere origin per repo =========================== -# Pe main comite schimbarile ca "sync SVN r", apoi fetch + ff/rebase fata de origin/main -# (sync-urile cu continut deja identic pe origin devin goale la rebase si dispar) si push -# DOAR daca tot ahead-ul e din commit-uri de sync. Intoarce starea pasilor. -function Sync-Repo { - param([string]$RepoDir, [string]$Rev, [string]$Label) - # EAP local Continue: git scrie normal pe stderr (fetch/push/rebase), iar sub Stop - # redirectarea 2>$null ar arunca NativeCommandError in PS 5.1; verificam $LASTEXITCODE. - $ErrorActionPreference = 'Continue' - $r = [PSCustomObject]@{ Commit='nimic'; Origin='-'; Push='-'; Warnings=@() } - if (-not (Test-Path -LiteralPath (Join-Path $RepoDir '.git'))) { - Write-Host " ${Label}: fara repo git ($RepoDir) - sar peste." - $r.Commit = 'fara-repo' - return $r - } - $branch = (& git -C $RepoDir rev-parse --abbrev-ref HEAD).Trim() - if ($branch -ne 'main') { - # tree curat = putem trece pe main; altfel nu atingem branch-ul - $dirty = @(& git -C $RepoDir status --porcelain).Count -gt 0 - if ($dirty) { - Write-Host " ${Label}: esti pe '$branch'; sync-ul se face pe main. Ai modificari necomise - sar peste." - $r.Commit = 'skip-branch' - return $r - } - Write-Host " ${Label}: pe '$branch' cu tree curat - fac checkout main." - & git -C $RepoDir checkout main | Out-Null - if ($LASTEXITCODE -ne 0) { - Write-Host " ${Label}: checkout main a esuat - sar peste." - $r.Commit = 'skip-branch' - return $r - } - } - & git -C $RepoDir add -A | Out-Null - $staged = @(& git -C $RepoDir status --porcelain).Count -gt 0 - if ($staged) { - $msg = if ($Rev) { "sync SVN r$Rev" } else { "sync SVN" } - & git -C $RepoDir commit -m $msg | Out-Null - if ($LASTEXITCODE -ne 0) { - Write-Host " ${Label}: commit a esuat - sar peste reconciliere." - $r.Commit = 'esec-commit' - $r.Warnings += "${Label}: commit de sync esuat" - return $r - } - Write-Host " ${Label}: commit '$msg'." - $r.Commit = 'commit' - } else { - Write-Host " ${Label}: nimic de comis." - } - - # --- reconciliere cu origin (dupa commit: tree curat, fisierele noi sunt deja urmarite) --- - $originUrl = (& git -C $RepoDir remote get-url origin 2>$null | Out-String).Trim() - if ($LASTEXITCODE -ne 0 -or -not $originUrl) { - Write-Host " ${Label}: fara remote origin - repo doar local, sar peste reconciliere." - $r.Origin = 'fara-origin' - return $r - } - & git -C $RepoDir fetch origin 2>$null | Out-Null - if ($LASTEXITCODE -ne 0) { - Write-Host " ${Label}: AVERTISMENT: git fetch origin a esuat (offline / gitea inaccesibil?); reconcilierea ramane pe urmatoarea rulare." - $r.Origin = 'fetch-esuat' - $r.Warnings += "${Label}: fetch origin esuat - reconciliere amanata" - return $r - } - & git -C $RepoDir rev-parse --verify --quiet origin/main 2>$null | Out-Null - if ($LASTEXITCODE -ne 0) { - Write-Host " ${Label}: origin nu are inca main - sar peste reconciliere." - $r.Origin = 'fara-origin-main' - return $r - } - - for ($attempt = 1; $attempt -le 3; $attempt++) { - $behind = [int]((& git -C $RepoDir rev-list --count main..origin/main | Out-String).Trim()) - $ahead = [int]((& git -C $RepoDir rev-list --count origin/main..main | Out-String).Trim()) - if ($behind -gt 0 -and $ahead -eq 0) { - & git -C $RepoDir merge --ff-only origin/main 2>$null | Out-Null - if ($LASTEXITCODE -ne 0) { - Write-Host " ${Label}: AVERTISMENT: fast-forward la origin/main a esuat neasteptat - verifica manual." - $r.Origin = 'conflict' - $r.Warnings += "${Label}: fast-forward esuat - verifica manual repo-ul" - return $r - } - Write-Host " ${Label}: adus la zi cu origin/main (fast-forward, $behind commit-uri)." - $r.Origin = 'ff' - } elseif ($behind -gt 0 -and $ahead -gt 0) { - Write-Host " ${Label}: local si origin au divergat (ahead $ahead / behind $behind) - rebase pe origin/main." - & git -C $RepoDir rebase --empty=drop origin/main 2>$null | Out-Null - if ($LASTEXITCODE -ne 0) { - & git -C $RepoDir rebase --abort 2>$null | Out-Null - Write-Host " ${Label}: CONFLICT real la rebase pe origin/main - rebase anulat. Rezolva manual: git -C $RepoDir rebase origin/main" - $r.Origin = 'conflict' - $r.Warnings += "${Label}: conflict real cu origin/main - reconciliere manuala necesara" - return $r - } - $r.Origin = 'rebase' - } elseif ($r.Origin -eq '-') { - $r.Origin = if ($ahead -gt 0) { 'doar-ahead' } else { 'la-zi' } - } - - # --- push doar daca tot ahead-ul e din commit-uri de sync --- - $aheadMsgs = @(& git -C $RepoDir log --format=%s origin/main..main) | Where-Object { $_ -and $_.Trim() } - if ($aheadMsgs.Count -eq 0) { - Write-Host " ${Label}: la zi cu origin/main; nimic de impins." - $r.Push = 'nimic' - return $r - } - $nonSync = @($aheadMsgs | Where-Object { $_ -notmatch '^sync SVN( r\S+)?$' }) - if ($nonSync.Count -gt 0) { - Write-Host " ${Label}: AVERTISMENT: ahead de origin include commit-uri non-sync - NU fac push automat (push manual dupa review):" - $nonSync | Select-Object -First 5 | ForEach-Object { Write-Host " - $_" } - $r.Push = 'sarit-non-sync' - $r.Warnings += "${Label}: push sarit - exista commit-uri non-sync nepushed" - return $r - } - & git -C $RepoDir push origin main 2>$null | Out-Null - if ($LASTEXITCODE -eq 0) { - Write-Host " ${Label}: push origin main ($($aheadMsgs.Count) commit-uri de sync)." - $r.Push = 'push' - return $r - } - if ($attempt -lt 3) { - Write-Host " ${Label}: push respins (probabil push simultan de pe alta masina) - refetch si reiau (incercarea $($attempt+1))." - & git -C $RepoDir fetch origin 2>$null | Out-Null - if ($LASTEXITCODE -ne 0) { - Write-Host " ${Label}: AVERTISMENT: refetch esuat dupa push respins." - $r.Push = 'esec' - $r.Warnings += "${Label}: push esuat si refetch esuat - reconciliere la urmatoarea rulare" - return $r - } - } - } - Write-Host " ${Label}: AVERTISMENT: push respins de 3 ori - renunt; se reconciliaza la urmatoarea rulare." - $r.Push = 'esec' - $r.Warnings += "${Label}: push esuat dupa 3 incercari" - return $r -} - -Write-Host '' -Write-Host "--- 3. sync repo proiect ---" -$resProj = Sync-Repo -RepoDir $ProjectRoot -Rev $rev -Label 'proiect' - -Write-Host '' -Write-Host "--- 4. sync repo COMUN ---" -$revComun = '' -$resComun = [PSCustomObject]@{ Commit='nimic'; Origin='-'; Push='-'; Warnings=@() } -if (Test-Path -LiteralPath $comunRoot -PathType Container) { - if (-not $GitOnly) { $revComun = Get-SvnRev $comunRoot } - $resComun = Sync-Repo -RepoDir $comunRoot -Rev $revComun -Label 'COMUN' -} else { - Write-Host " COMUN: folderul nu exista ($comunRoot) - sar peste." -} - -# =========================== 5. inchidere branch-uri claude/* =========================== -# Inchide branch-urile claude/* al caror diff fata de main e gol (munca lor a intrat prin sync). -function Close-ClaudeBranches { - param([string]$RepoDir, [string]$Label) - $closed = @(); $active = @() - if (-not (Test-Path -LiteralPath (Join-Path $RepoDir '.git'))) { return @{ Closed=$closed; Active=$active } } - $branches = @(& git -C $RepoDir for-each-ref --format='%(refname:short)' refs/heads/claude 2>$null) | - Where-Object { $_ -and $_.Trim() } | ForEach-Object { $_.Trim() } - foreach ($b in $branches) { - $diff = @(& git -C $RepoDir diff --name-only main..$b 2>$null) | Where-Object { $_ -and $_.Trim() } - if ($diff.Count -eq 0) { - & git -C $RepoDir branch -D $b | Out-Null - if ($LASTEXITCODE -eq 0) { $closed += $b; Write-Host " ${Label}: inchis $b" } - else { Write-Host " ${Label}: nu am putut sterge $b" } - } else { - $active += $b - Write-Host " ${Label}: activ $b ($($diff.Count) fisiere diferite)" - } - } - return @{ Closed=$closed; Active=$active } -} - -Write-Host '' -Write-Host "--- 5. inchidere branch-uri claude/* ---" -$brProj = Close-ClaudeBranches -RepoDir $ProjectRoot -Label 'proiect' -$brComun = @{ Closed=@(); Active=@() } -if (Test-Path -LiteralPath $comunRoot -PathType Container) { - $brComun = Close-ClaudeBranches -RepoDir $comunRoot -Label 'COMUN' -} - -# =========================== 6. sumar =========================== -$commits = @() -if ($resProj.Commit -eq 'commit') { $commits += "proiect: sync SVN$(if($rev){" r$rev"})" } -if ($resComun.Commit -eq 'commit') { $commits += "COMUN: sync SVN$(if($revComun){" r$revComun"})" } -$closedAll = @($brProj.Closed + $brComun.Closed) -$activeAll = @($brProj.Active + $brComun.Active) -$warnAll = @($resProj.Warnings + $resComun.Warnings) - -Write-Host '' -Write-Host "===================== SUMAR =====================" -Write-Host "Revizie SVN: proiect=$(if($rev){$rev}else{'?'})$(if($revComun){" COMUN=$revComun"})" -if ($commits.Count -gt 0) { - Write-Host "Commit-uri de sync:" - $commits | ForEach-Object { Write-Host " $_" } -} else { - Write-Host "Commit-uri de sync: nimic de sincronizat" -} -Write-Host "Origin: proiect=$($resProj.Origin)/push=$($resProj.Push) COMUN=$($resComun.Origin)/push=$($resComun.Push)" -Write-Host "Branch-uri inchise: $(if($closedAll.Count){$closedAll -join ', '}else{'niciunul'})" -Write-Host "Branch-uri active: $(if($activeAll.Count){$activeAll -join ', '}else{'niciunul'})" -if ($warnAll.Count -gt 0) { - Write-Host "AVERTISMENTE:" - $warnAll | ForEach-Object { Write-Host " $_" } -} -Write-Host "================================================" -if (($resProj.Origin -eq 'conflict') -or ($resComun.Origin -eq 'conflict')) { exit 1 } -exit 0 +Write-Host "NOTA: roa_sync.ps1 s-a mutat in COMUN\scripts\. Actualizeaza lansatorul sa cheme direct: $target" +$extra = @() +if ($GitOnly) { $extra += '-GitOnly' } +& powershell -ExecutionPolicy Bypass -NoProfile -File $target -ProjectRoot $ProjectRoot @extra +exit $LASTEXITCODE diff --git a/test_roa_sync.ps1 b/test_roa_sync.ps1 deleted file mode 100644 index f6061d9..0000000 --- a/test_roa_sync.ps1 +++ /dev/null @@ -1,239 +0,0 @@ -<# -.SYNOPSIS - Teste standalone (fara Pester) pentru reconcilierea cu origin din roa_sync.ps1, pe - fixture-uri git construite in TEMP (origin bare + doua clone "masini"). Ruleaza - roa_sync.ps1 -GitOnly (fara SVN, fara FoxBin2Prg), deci nu atinge niciun proiect real. - - Scenarii: - (A) scenariul din 2026-07-27: modificari locale necomise + fisier netracked, toate - byte-identice cu ce a impins deja alta masina -> reconciliere automata (sync-ul - local devine gol la rebase si e aruncat), fara interventie manuala, exit 0; - (B) behind + continut local NOU -> rebase pastreaza sync-ul si il impinge pe origin; - (C) doar behind, fara modificari locale -> fast-forward la origin/main; - (D) conflict real (acelasi fisier, continut diferit) -> rebase --abort, exit nenul, - repo lasat curat (fara rebase in curs), commit-ul local pastrat; - (E) garda de push: commit non-sync ahead de origin -> push blocat + avertisment; - (F) fetch esuat (origin inaccesibil) -> comportamentul vechi (doar commit local), exit 0; - (G) push respins o data (hook pre-receive, simuleaza push simultan) -> retry reuseste; - (H) repo fara remote origin -> doar commit local, exit 0. -#> -[CmdletBinding()] -param() - -$ErrorActionPreference = 'Stop' -$script:RoaSync = 'D:\ROA\UTIL\foxbin2prg\roa_sync.ps1' -$script:Failures = @() - -function Assert([bool]$cond, [string]$msg) { - if ($cond) { Write-Host " PASS: $msg" -ForegroundColor Green } - else { Write-Host " FAIL: $msg" -ForegroundColor Red; $script:Failures += $msg } -} - -# --- git in fixture: EAP Continue local (git scrie pe stderr; sub Stop 2>$null ar arunca) --- -function G { - param([Parameter(Mandatory)][string]$Repo, - [Parameter(Mandatory, ValueFromRemainingArguments)][string[]]$GitArgs) - $prev = $ErrorActionPreference; $ErrorActionPreference = 'Continue' - $out = (& git -C $Repo @GitArgs 2>$null | Out-String).Trim() - $code = $LASTEXITCODE - $ErrorActionPreference = $prev - if ($code -ne 0) { throw "git -C $Repo $($GitArgs -join ' ') a esuat (exit $code)" } - return $out -} - -# scriere fisier cu octeti determinati (acelasi continut => aceiasi octeti pe ambele "masini") -function WF([string]$path, [string]$content) { [IO.File]::WriteAllText($path, $content) } - -function Set-RepoConfig([string]$repo) { - $null = G $repo config user.name 'Test ROA' - $null = G $repo config user.email 'test@roa.local' - $null = G $repo config commit.gpgsign false - $null = G $repo config core.autocrlf false -} - -# --- lume de test: origin bare + masinaA (a impins deja) + masinaB (fixture-ul testat) --- -function New-World([string]$tag) { - $root = Join-Path $env:TEMP ("rs_test_{0}_{1}_{2}" -f $tag, $PID, [Guid]::NewGuid().ToString('N').Substring(0,8)) - New-Item -ItemType Directory -Force -Path $root | Out-Null - $bare = Join-Path $root 'origin.git' - $null = G $root init --bare origin.git - $null = G $bare symbolic-ref HEAD refs/heads/main - # -c la clone seteaza configul in noul repo INAINTE de checkout: cu autocrlf global true, - # checkout-ul ar scrie CRLF si un add -A ulterior ar vedea fals toate fisierele modificate - $null = G $root clone -c core.autocrlf=false origin.git masinaA - $A = Join-Path $root 'masinaA' - Set-RepoConfig $A - $null = G $A checkout -b main - WF (Join-Path $A 'a.prg') "linie 1`nv1`n" - WF (Join-Path $A 'b.prg') "b v1`n" - $null = G $A add -A - $null = G $A commit -m 'initial' - $null = G $A push -u origin main - $null = G $root clone -c core.autocrlf=false origin.git masinaB - $B = Join-Path $root 'masinaB' - Set-RepoConfig $B - return [PSCustomObject]@{ Root=$root; Bare=$bare; A=$A; B=$B } -} - -function Remove-World($w) { - Remove-Item -Recurse -Force -LiteralPath $w.Root -ErrorAction SilentlyContinue -} - -function Invoke-RoaSync([string]$Fixture) { - $prev = $ErrorActionPreference; $ErrorActionPreference = 'Continue' - $raw = & powershell -ExecutionPolicy Bypass -NoProfile -File $script:RoaSync -ProjectRoot $Fixture -GitOnly 2>&1 | Out-String - $exit = $LASTEXITCODE - $ErrorActionPreference = $prev - return [PSCustomObject]@{ Exit=$exit; Raw=$raw } -} - -# ============================== SCENARIILE ============================== - -function Test-ContinutIdentic { - Write-Host "`n--- (A) scenariul 2026-07-27: local byte-identic cu origin (modificat + netracked) ---" - $w = New-World 'ident' - try { - # masina A a facut svn update + sync + push inaintea noastra - WF (Join-Path $w.A 'a.prg') "linie 1`nv2`n" - WF (Join-Path $w.A 'wincrypt.h') "#define W 1`n" - $null = G $w.A add -A; $null = G $w.A commit -m 'sync SVN r100'; $null = G $w.A push origin main - # masina B: acelasi svn update + regenerare => aceleasi continuturi, necomise/netracked - WF (Join-Path $w.B 'a.prg') "linie 1`nv2`n" - WF (Join-Path $w.B 'wincrypt.h') "#define W 1`n" - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -eq 0) "A: exit 0, fara interventie manuala (exit=$($r.Exit))" - Assert ((G $w.B rev-parse main) -eq (G $w.Bare rev-parse main)) "A: main local == origin/main dupa reconciliere" - Assert ((G $w.B log -1 --format=%s) -eq 'sync SVN r100') "A: sync-ul local gol a fost aruncat (tip = commit-ul masinii A)" - Assert ([string]::IsNullOrWhiteSpace((G $w.B status --porcelain))) "A: working tree curat" - } finally { Remove-World $w } -} - -function Test-ContinutNou { - Write-Host "`n--- (B) behind + continut local nou: rebase pastreaza sync-ul si il impinge ---" - $w = New-World 'nou' - try { - WF (Join-Path $w.A 'a.prg') "linie 1`nv2`n" - $null = G $w.A add -A; $null = G $w.A commit -m 'sync SVN r100'; $null = G $w.A push origin main - # masina B: aceeasi modificare (identica) + un fisier NOU pe care origin nu il are - WF (Join-Path $w.B 'a.prg') "linie 1`nv2`n" - WF (Join-Path $w.B 'c.prg') "continut nou local`n" - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -eq 0) "B: exit 0 (exit=$($r.Exit))" - Assert ((G $w.B log -1 --format=%s) -eq 'sync SVN') "B: sync-ul local (continut nou) pastrat dupa rebase" - Assert ((G $w.B rev-parse main) -eq (G $w.Bare rev-parse main)) "B: push automat - origin/main actualizat" - Assert ((G $w.Bare ls-tree --name-only main) -match 'c\.prg') "B: c.prg a ajuns pe origin" - } finally { Remove-World $w } -} - -function Test-DoarBehind { - Write-Host "`n--- (C) doar behind, fara modificari locale: fast-forward ---" - $w = New-World 'ff' - try { - WF (Join-Path $w.A 'b.prg') "b v2`n" - $null = G $w.A add -A; $null = G $w.A commit -m 'sync SVN r101'; $null = G $w.A push origin main - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -eq 0) "C: exit 0 (exit=$($r.Exit))" - Assert ($r.Raw -match 'fast-forward') "C: reconciliere prin fast-forward" - Assert ((G $w.B rev-parse main) -eq (G $w.Bare rev-parse main)) "C: main local == origin/main" - } finally { Remove-World $w } -} - -function Test-ConflictReal { - Write-Host "`n--- (D) conflict real: rebase abortat, exit nenul, repo curat ---" - $w = New-World 'conf' - try { - WF (Join-Path $w.A 'a.prg') "linie 1`nvarianta A`n" - $null = G $w.A add -A; $null = G $w.A commit -m 'sync SVN r102'; $null = G $w.A push origin main - WF (Join-Path $w.B 'a.prg') "linie 1`nvarianta B`n" - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -ne 0) "D: exit nenul la conflict real (exit=$($r.Exit))" - Assert ($r.Raw -match 'CONFLICT') "D: conflictul e raportat explicit" - $inRebase = (Test-Path (Join-Path $w.B '.git\rebase-merge')) -or (Test-Path (Join-Path $w.B '.git\rebase-apply')) - Assert (-not $inRebase) "D: rebase anulat curat (fara rebase in curs)" - Assert ((G $w.B log -1 --format=%s) -eq 'sync SVN') "D: commit-ul local de sync pastrat" - Assert ([string]::IsNullOrWhiteSpace((G $w.B status --porcelain))) "D: working tree curat dupa abort" - Assert ((G $w.Bare log -1 --format=%s) -eq 'sync SVN r102') "D: origin neatins" - } finally { Remove-World $w } -} - -function Test-GardaNonSync { - Write-Host "`n--- (E) garda de push: commit non-sync ahead blocheaza push-ul automat ---" - $w = New-World 'guard' - try { - $init = G $w.Bare rev-parse main - # commit local non-sync (lucrare in curs, nepushed) + modificari de sync necomise - WF (Join-Path $w.B 'd.prg') "lucru manual`n" - $null = G $w.B add -A; $null = G $w.B commit -m 'lucrare manuala neaprobata' - WF (Join-Path $w.B 'b.prg') "b v2`n" - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -eq 0) "E: exit 0 (exit=$($r.Exit))" - Assert ($r.Raw -match 'non-sync') "E: avertisment despre commit-uri non-sync" - Assert ((G $w.Bare rev-parse main) -eq $init) "E: origin neatins (fara push)" - Assert ((G $w.B log -1 --format=%s) -eq 'sync SVN') "E: sync-ul local totusi comis" - } finally { Remove-World $w } -} - -function Test-Offline { - Write-Host "`n--- (F) fetch esuat (origin inaccesibil): doar commit local, exit 0 ---" - $w = New-World 'off' - try { - $null = G $w.B remote set-url origin (Join-Path $w.Root 'inexistent.git') - WF (Join-Path $w.B 'b.prg') "b v3`n" - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -eq 0) "F: exit 0 (exit=$($r.Exit))" - Assert ($r.Raw -match 'fetch origin a esuat') "F: avertisment de fetch esuat" - Assert ((G $w.B log -1 --format=%s) -eq 'sync SVN') "F: commit-ul local de sync facut totusi" - } finally { Remove-World $w } -} - -function Test-PushRetry { - Write-Host "`n--- (G) push respins o data (simulare push simultan): retry reuseste ---" - $w = New-World 'retry' - try { - # hook pre-receive: respinge cat timp exista flagul reject_once, apoi accepta - $hook = "#!/bin/sh`nif [ -f reject_once ]; then`n rm -f reject_once`n exit 1`nfi`nexit 0`n" - [IO.File]::WriteAllText((Join-Path $w.Bare 'hooks\pre-receive'), $hook) - WF (Join-Path $w.Bare 'reject_once') "1" - WF (Join-Path $w.B 'b.prg') "b v4`n" - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -eq 0) "G: exit 0 (exit=$($r.Exit))" - Assert ($r.Raw -match 'push respins') "G: prima incercare respinsa si raportata" - Assert ((G $w.Bare rev-parse main) -eq (G $w.B rev-parse main)) "G: push reusit la reincercare" - } finally { Remove-World $w } -} - -function Test-FaraOrigin { - Write-Host "`n--- (H) repo fara remote origin: doar commit local ---" - $w = New-World 'noorig' - try { - $null = G $w.B remote remove origin - WF (Join-Path $w.B 'b.prg') "b v5`n" - $r = Invoke-RoaSync $w.B - Assert ($r.Exit -eq 0) "H: exit 0 (exit=$($r.Exit))" - Assert ($r.Raw -match 'fara remote origin') "H: lipsa origin raportata" - Assert ((G $w.B log -1 --format=%s) -eq 'sync SVN') "H: commit-ul local de sync facut" - } finally { Remove-World $w } -} - -# ============================== MAIN ============================== -if (-not (Test-Path -LiteralPath $script:RoaSync)) { throw "Nu gasesc roa_sync.ps1: $script:RoaSync" } - -Write-Host "=== test_roa_sync.ps1 ===" -Test-ContinutIdentic -Test-ContinutNou -Test-DoarBehind -Test-ConflictReal -Test-GardaNonSync -Test-Offline -Test-PushRetry -Test-FaraOrigin - -Write-Host "`n=== REZULTAT ===" -if ($script:Failures.Count -eq 0) { - Write-Host "TOATE testele au trecut." -ForegroundColor Green - exit 0 -} else { - Write-Host "$($script:Failures.Count) test(e) esuate:" -ForegroundColor Red - $script:Failures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red } - exit 1 -}