How to extend the "New Review Request" page

0 views
Skip to first unread message

Roland Kächele

unread,
Nov 29, 2025, 10:41:50 AM (7 days ago) Nov 29
to Review Board Development
I'm trying to extend the "New Review Request" page for reviewing complete files from a subversion or git repo.

I have tried TemplateHook and URLHook but my extension isn't showed on the page.

   ```
from reviewboard.extensions.base import Extension
from django.urls import path
from django.utils.translation import gettext_lazy as _
from reviewboard.extensions.base import ExtensionManager
from reviewboard.site.urlresolvers import local_site_reverse
from django.http import JsonResponse
from django.shortcuts import render
from reviewboard.scmtools.models import Repository  # updated import
from djblets.extensions.hooks import TemplateHook
import os
import subprocess
import logging

logger = logging.getLogger("reviewboard.extensions.FileReview")

class FileReviewExtension(Extension):
    metadata = {
        'Name': 'FileReview',
        'Summary': _('Review complete files from a repository'),
        'Author': 'Roland',
        'Version': '0.1.0',
    }

    def initialize(self):
        logger.info("Initializing FileReviewExtension and registering URL patterns.")
        self.url_patterns = [
            path(
                'filereview/new/',
                self.create_file_review_request,
                name='filereview-new'
            ),
            path(
                'filereview/list-files/',
                self.list_repo_files,
                name='filereview-list-files'
            ),
        ]
        logger.debug("URL patterns registered: %s", self.url_patterns)
        # Inject a link into the main content area of the New Review Request page
        TemplateHook(
            self,
            "new-review-request-main",
            "filereview/navbar_link.html"
        )

    def create_file_review_request(self, request):
        logger.info("Accessed create_file_review_request view with method: %s", request.method)
        if request.method == 'POST':
            repo_id = request.POST.get('repository')
            file_paths = request.POST.getlist('files')
            logger.info("Received POST for repo_id=%s, files=%s", repo_id, file_paths)
            # ...logic to create a review request for selected files...
            return JsonResponse({'success': True, 'files': file_paths})
        else:
            repositories = Repository.objects.all()
            logger.info("Fetched %d repositories.", repositories.count())
            file_select_repos = [
                repo for repo in repositories
                if getattr(repo, 'tool', None) and getattr(repo.tool, 'name', '').lower() in ('git', 'subversion')
            ]
            logger.info("Filtered %d file-selectable repositories (Git/SVN).", len(file_select_repos))
            return render(request, 'filereview/new_review_request.html', {
                'repositories': repositories,
                'file_select_repos': file_select_repos,
            })

    def list_repo_files(self, request):
        repo_id = request.GET.get('repository')
        logger.info("Listing files for repository id: %s", repo_id)
        try:
            repo = Repository.objects.get(pk=repo_id)
        except Repository.DoesNotExist:
            logger.error("Repository with id %s does not exist.", repo_id)
            return JsonResponse({'files': [], 'error': 'Repository not found'}, status=404)
        files = []

        tool = getattr(repo, 'tool', None)
        tool_name = getattr(tool, 'name', '').lower() if tool else ''
        repo_path = repo.path
        username = getattr(repo, 'username', None)
        password = getattr(repo, 'password', None)

        logger.info("Repository type: %s, path: %s", tool_name, repo_path)

        if tool_name == 'git':
            try:
                logger.info("Attempting to list files from Git repository.")
                if username and password and repo_path.startswith('http'):
                    from urllib.parse import urlparse, urlunparse
                    parts = urlparse(repo_path)
                    netloc = f"{username}:{password}@{parts.hostname}"
                    if parts.port:
                        netloc += f":{parts.port}"
                    repo_url = urlunparse((parts.scheme, netloc, parts.path, parts.params, parts.query, parts.fragment))
                else:
                    repo_url = repo_path

                ref_hash_output = subprocess.check_output(
                    ['git', 'ls-remote', repo_url, 'refs/heads/master'],
                    universal_newlines=True
                )
                ref_hash = ref_hash_output.split('\t')[0].strip()
                files_output = subprocess.check_output(
                    ['git', 'ls-tree', '-r', '--name-only', ref_hash],
                    universal_newlines=True
                )
                files = [f for f in files_output.strip().split('\n') if f]
                logger.info("Found %d files in Git repository.", len(files))
            except Exception as e:
                logger.error("Error listing files from Git: %s", e)
                files = []
        elif tool_name == 'subversion':
            try:
                logger.info("Attempting to list files from SVN repository.")
                svn_cmd = ['svn', 'list', '-R', repo_path]
                if username:
                    svn_cmd.extend(['--username', username])
                if password:
                    svn_cmd.extend(['--password', password])
                output = subprocess.check_output(
                    svn_cmd,
                    universal_newlines=True
                )
                files = [line.strip() for line in output.splitlines() if line and not line.endswith('/')]
                logger.info("Found %d files in SVN repository.", len(files))
            except Exception as e:
                logger.error("Error listing files from SVN: %s", e)
                files = []
        else:
            logger.warning("Repository type %s is not supported for file listing.", tool_name)
            files = []

        return JsonResponse({'files': files})
   ```

In reviewboard.log I see that my extension is initialized but other log infos aren't shown.

Is it possible to enhance the page or ReviewBoard 7.0.3 doesn't support this enhancement?

Has someone suggestions for corrections?

BR
Roland

Reply all
Reply to author
Forward
0 new messages