@@ -1450,44 +1450,56 @@
1450 1450 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
messages.info(request, "Sync disabled.")
1451 1451 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
from django.shortcuts import redirect
1452 1452 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
1453 1453 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return redirect("fossil:sync", slug=slug)
1454 1454 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
1455 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- elif action == "push" and fossil_repo.remote_url:
1456 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if cli.is_available():
1457 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- cli.ensure_default_user(fossil_repo.full_path)
1458 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- result = cli.push(fossil_repo.full_path)
1459 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from django.contrib import messages
1460 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
1461 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if result["success"]:
1462 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from django.utils import timezone
1463 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
1464 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- fossil_repo.last_sync_at = timezone.now()
1465 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- fossil_repo.save(update_fields=["last_sync_at", "updated_at", "version"])
1466 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if result.get("artifacts_sent", 0) > 0:
1467 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- messages.success(request, f"Pushed {result['artifacts_sent']} artifacts to remote.")
1468 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- else:
1469 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- messages.info(request, "Remote is already up to date.")
1470 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- else:
1471 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- messages.error(request, f"Push failed: {result.get('message', 'Unknown error')}")
1472 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
1473 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- elif action == "sync_bidirectional" and fossil_repo.remote_url:
1474 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if cli.is_available():
1475 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- cli.ensure_default_user(fossil_repo.full_path)
1476 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- result = cli.sync(fossil_repo.full_path)
1477 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from django.contrib import messages
1478 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from django.utils import timezone
1479 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
1480 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if result["success"]:
1481 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- fossil_repo.last_sync_at = timezone.now()
1482 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- with reader:
1483 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- fossil_repo.checkin_count = reader.get_checkin_count()
1484 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- fossil_repo.file_size_bytes = fossil_repo.full_path.stat().st_size
1485 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- fossil_repo.save(update_fields=["last_sync_at", "checkin_count", "file_size_bytes", "updated_at", "version"])
1486 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- messages.success(request, "Bidirectional sync complete.")
1487 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- else:
1488 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- messages.error(request, f"Sync failed: {result.get('message', 'Unknown error')}")
1455 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ elif action in ("push", "sync_bidirectional") and fossil_repo.remote_url:
1456 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from django.contrib import messages
1457 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
1458 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from projects.access import can_admin_project
1459 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
1460 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Enforce branch protection — non-admins blocked if any protected branch restricts push
1461 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ push_blocked = False
1462 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if not can_admin_project(request.user, project):
1463 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from fossil.branch_protection import BranchProtection
1464 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
1465 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ has_restrictions = BranchProtection.objects.filter(repository=fossil_repo, restrict_push=True, deleted_at__isnull=True).exists()
1466 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if has_restrictions:
1467 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ push_blocked = True
1468 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.error(
1469 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ request,
1470 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "Push blocked: branch protection rules restrict push to admins only.",
1471 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
1472 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
1473 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if not push_blocked and cli.is_available():
1474 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ cli.ensure_default_user(fossil_repo.full_path)
1475 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if action == "push":
1476 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = cli.push(fossil_repo.full_path)
1477 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if result["success"]:
1478 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from django.utils import timezone
1479 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
1480 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fossil_repo.last_sync_at = timezone.now()
1481 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fossil_repo.save(update_fields=["last_sync_at", "updated_at", "version"])
1482 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if result.get("artifacts_sent", 0) > 0:
1483 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.success(request, f"Pushed {result['artifacts_sent']} artifacts to remote.")
1484 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ else:
1485 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.info(request, "Remote is already up to date.")
1486 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ else:
1487 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.error(request, f"Push failed: {result.get('message', 'Unknown error')}")
1488 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ else:
1489 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = cli.sync(fossil_repo.full_path)
1490 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if result["success"]:
1491 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from django.utils import timezone
1492 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
1493 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fossil_repo.last_sync_at = timezone.now()
1494 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with reader:
1495 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fossil_repo.checkin_count = reader.get_checkin_count()
1496 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fossil_repo.file_size_bytes = fossil_repo.full_path.stat().st_size
1497 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fossil_repo.save(update_fields=["last_sync_at", "checkin_count", "file_size_bytes", "updated_at", "version"])
1498 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.success(request, "Bidirectional sync complete.")
1499 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ else:
1500 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ messages.error(request, f"Sync failed: {result.get('message', 'Unknown error')}")
1489 1501 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
1490 1502 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
elif action == "pull" and fossil_repo.remote_url:
1491 1503 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if cli.is_available():
1492 1504 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
cli.ensure_default_user(fossil_repo.full_path)
1493 1505 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
result = cli.pull(fossil_repo.full_path)
1494 1506 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!