Add version control system functionality with branch management, history tracking, and merge operations

This commit is contained in:
pacnpal
2025-02-06 19:29:23 -05:00
parent 6fa807f4b6
commit f3d28817a5
26 changed files with 2935 additions and 508 deletions

View File

@@ -1,3 +1,237 @@
from django.shortcuts import render
from django.views.generic import TemplateView, View
from django.http import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import ValidationError
from django.db import transaction
# Create your views here.
from .models import VersionBranch, VersionTag, ChangeSet
from .managers import BranchManager, ChangeTracker, MergeStrategy
class VersionControlPanel(LoginRequiredMixin, TemplateView):
"""Main version control interface"""
template_name = 'history_tracking/version_control_panel.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
branch_manager = BranchManager()
context.update({
'branches': branch_manager.list_branches(),
'current_branch': self.request.GET.get('branch'),
})
return context
class BranchListView(LoginRequiredMixin, View):
"""HTMX view for branch list"""
def get(self, request):
branch_manager = BranchManager()
branches = branch_manager.list_branches()
content = render_to_string(
'history_tracking/components/branch_list.html',
{'branches': branches},
request=request
)
return HttpResponse(content)
class HistoryView(LoginRequiredMixin, View):
"""HTMX view for change history"""
def get(self, request):
branch_name = request.GET.get('branch')
if not branch_name:
return HttpResponse("No branch selected")
branch = get_object_or_404(VersionBranch, name=branch_name)
tracker = ChangeTracker()
changes = tracker.get_changes(branch)
content = render_to_string(
'history_tracking/components/history_view.html',
{'changes': changes},
request=request
)
return HttpResponse(content)
class MergeView(LoginRequiredMixin, View):
"""HTMX view for merge operations"""
def get(self, request):
source = request.GET.get('source')
target = request.GET.get('target')
if not (source and target):
return HttpResponse("Source and target branches required")
content = render_to_string(
'history_tracking/components/merge_panel.html',
{
'source': source,
'target': target
},
request=request
)
return HttpResponse(content)
@transaction.atomic
def post(self, request):
source_name = request.POST.get('source')
target_name = request.POST.get('target')
if not (source_name and target_name):
return JsonResponse({
'error': 'Source and target branches required'
}, status=400)
try:
source = get_object_or_404(VersionBranch, name=source_name)
target = get_object_or_404(VersionBranch, name=target_name)
branch_manager = BranchManager()
success, conflicts = branch_manager.merge_branches(
source=source,
target=target,
user=request.user
)
if success:
content = render_to_string(
'history_tracking/components/merge_success.html',
{'source': source, 'target': target},
request=request
)
return HttpResponse(content)
else:
content = render_to_string(
'history_tracking/components/merge_conflicts.html',
{
'source': source,
'target': target,
'conflicts': conflicts
},
request=request
)
return HttpResponse(content)
except ValidationError as e:
return JsonResponse({'error': str(e)}, status=400)
except Exception as e:
return JsonResponse(
{'error': 'Merge failed. Please try again.'},
status=500
)
class BranchCreateView(LoginRequiredMixin, View):
"""HTMX view for branch creation"""
def get(self, request):
content = render_to_string(
'history_tracking/components/branch_create.html',
request=request
)
return HttpResponse(content)
@transaction.atomic
def post(self, request):
name = request.POST.get('name')
parent_name = request.POST.get('parent')
if not name:
return JsonResponse({'error': 'Branch name required'}, status=400)
try:
branch_manager = BranchManager()
parent = None
if parent_name:
parent = get_object_or_404(VersionBranch, name=parent_name)
branch = branch_manager.create_branch(
name=name,
parent=parent,
user=request.user
)
content = render_to_string(
'history_tracking/components/branch_item.html',
{'branch': branch},
request=request
)
return HttpResponse(content)
except ValidationError as e:
return JsonResponse({'error': str(e)}, status=400)
except Exception as e:
return JsonResponse(
{'error': 'Branch creation failed. Please try again.'},
status=500
)
class TagCreateView(LoginRequiredMixin, View):
"""HTMX view for version tagging"""
def get(self, request):
branch_name = request.GET.get('branch')
if not branch_name:
return HttpResponse("Branch required")
content = render_to_string(
'history_tracking/components/tag_create.html',
{'branch_name': branch_name},
request=request
)
return HttpResponse(content)
@transaction.atomic
def post(self, request):
name = request.POST.get('name')
branch_name = request.POST.get('branch')
if not (name and branch_name):
return JsonResponse(
{'error': 'Tag name and branch required'},
status=400
)
try:
branch = get_object_or_404(VersionBranch, name=branch_name)
# Get latest historical record for the branch
latest_change = ChangeSet.objects.filter(
branch=branch,
status='applied'
).latest('created_at')
if not latest_change:
return JsonResponse(
{'error': 'No changes to tag'},
status=400
)
tag = VersionTag.objects.create(
name=name,
branch=branch,
historical_record=latest_change.historical_records.latest('history_date'),
created_by=request.user,
metadata={
'tagged_at': timezone.now().isoformat(),
'changeset': latest_change.pk
}
)
content = render_to_string(
'history_tracking/components/tag_item.html',
{'tag': tag},
request=request
)
return HttpResponse(content)
except ValidationError as e:
return JsonResponse({'error': str(e)}, status=400)
except Exception as e:
return JsonResponse(
{'error': 'Tag creation failed. Please try again.'},
status=500
)