예제 #1
0
    def create(self,
               request,
               repository,
               basedir=None,
               local_site_name=None,
               base_commit_id=None,
               *args,
               **kwargs):
        """Validate a diff.

        This API has a similar signature to the ReviewRequest resource POST
        API, but instead of actually creating a review request, will return
        either OK or an error, depending on whether the included diff file
        parsed correctly.
        """
        local_site = self._get_local_site(local_site_name)

        path = request.FILES.get('path')
        parent_diff_path = request.FILES.get('parent_diff_path')

        try:
            query = Q(pk=int(repository), local_site=local_site)
        except ValueError:
            query = (Q(local_site=local_site)
                     & (Q(path=repository)
                        | Q(mirror_path=repository)
                        | Q(name=repository)))

        try:
            repository = Repository.objects.get(query)
        except Repository.DoesNotExist:
            return INVALID_REPOSITORY, {'repository': repository}
        except Repository.MultipleObjectsReturned:
            msg = ('Too many repositories matched "%s". '
                   'Try specifying the repository by name instead.' %
                   repository)

            return INVALID_REPOSITORY.with_message(msg), {
                'repository': repository,
            }

        if (not repository.get_scmtool().diffs_use_absolute_paths
                and basedir is None):

            return INVALID_FORM_DATA, {
                'fields': {
                    'basedir': ['Given repository requires a base directory'],
                },
            }

        if basedir is None:
            # If we get here, the repository uses absolute paths. Deeper down
            # (where we don't necessarily know about the details of the
            # repository), we do an os.path.join() with the basedir value,
            # which will choke if it's None.
            basedir = ''

        try:
            DiffSet.objects.create_from_upload(repository,
                                               path,
                                               parent_diff_path,
                                               None,
                                               basedir,
                                               request,
                                               base_commit_id=base_commit_id,
                                               save=False)
        except FileNotFoundError as e:
            return REPO_FILE_NOT_FOUND, {
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except EmptyDiffError:
            return DIFF_EMPTY
        except DiffTooBigError as e:
            return DIFF_TOO_BIG, {
                'reason': six.text_type(e),
                'max_size': e.max_diff_size,
            }
        except DiffParserError as e:
            return DIFF_PARSE_ERROR, {
                'reason': six.text_type(e),
                'linenum': e.linenum,
            }
        except ShortSHA1Error as e:
            return REPO_FILE_NOT_FOUND, {
                'reason': six.text_type(e),
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except SCMError as e:
            return DIFF_PARSE_ERROR.with_message(six.text_type(e))
        except Exception as e:
            logging.exception('Unexpected error when validating diff.')

            return DIFF_PARSE_ERROR.with_message(
                'Unexpected error when validating the diff: %s' % e)

        return 200, {}
예제 #2
0
    def create(self, request, repository, basedir=None, local_site_name=None,
               base_commit_id=None, *args, **kwargs):
        """Validate a diff.

        This API has a similar signature to the ReviewRequest resource POST
        API, but instead of actually creating a review request, will return
        either OK or an error, depending on whether the included diff file
        parsed correctly.
        """
        local_site = self._get_local_site(local_site_name)

        path = request.FILES.get('path')
        parent_diff_path = request.FILES.get('parent_diff_path')

        try:
            query = Q(pk=int(repository), local_site=local_site)
        except ValueError:
            query = (Q(local_site=local_site)
                     & (Q(path=repository)
                        | Q(mirror_path=repository)
                        | Q(name=repository)))

        try:
            repository = Repository.objects.get(query)
        except Repository.DoesNotExist:
            return INVALID_REPOSITORY, {
                'repository': repository
            }
        except Repository.MultipleObjectsReturned:
            msg = ('Too many repositories matched "%s". '
                   'Try specifying the repository by name instead.'
                   % repository)

            return INVALID_REPOSITORY.with_message(msg), {
                'repository': repository,
            }

        if (not repository.get_scmtool().diffs_use_absolute_paths and
            basedir is None):

            return INVALID_FORM_DATA, {
                'fields': {
                    'basedir': ['Given repository requires a base directory'],
                },
            }

        if basedir is None:
            # If we get here, the repository uses absolute paths. Deeper down
            # (where we don't necessarily know about the details of the
            # repository), we do an os.path.join() with the basedir value,
            # which will choke if it's None.
            basedir = ''

        try:
            DiffSet.objects.create_from_upload(
                repository=repository,
                diff_file=path,
                parent_diff_file=parent_diff_path,
                basedir=basedir,
                request=request,
                base_commit_id=base_commit_id,
                validate_only=True)
        except FileNotFoundError as e:
            return REPO_FILE_NOT_FOUND, {
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except EmptyDiffError:
            return DIFF_EMPTY
        except DiffTooBigError as e:
            return DIFF_TOO_BIG, {
                'reason': six.text_type(e),
                'max_size': e.max_diff_size,
            }
        except DiffParserError as e:
            return DIFF_PARSE_ERROR, {
                'reason': six.text_type(e),
                'linenum': e.linenum,
            }
        except ShortSHA1Error as e:
            return REPO_FILE_NOT_FOUND, {
                'reason': six.text_type(e),
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except SCMError as e:
            return DIFF_PARSE_ERROR.with_message(six.text_type(e))
        except Exception as e:
            logging.exception('Unexpected error when validating diff.')

            return DIFF_PARSE_ERROR.with_message(
                'Unexpected error when validating the diff: %s' % e)

        return 200, {}
예제 #3
0
    def create(self,
               request,
               repository,
               commit_id,
               parent_id,
               base_commit_id=None,
               local_site_name=None,
               *args,
               **kwargs):
        """Validate a diff for a commit.

        This API has a similar signature to the :ref:`Draft DiffCommit resource
        <webapi2.0-draft-diff-commit-list-resource>` POST API, but instead of
        actually creating commits, it will return a result representing whether
        or not the included diff file parsed and validated correctly.

        This API must be called before posting to the :ref:`Draft DiffCommit
        resource <webapi2.0-draft-diff-commit-list-resource>` because the
        ``validation_info`` field returned by this resource is required for
        posting to that resource.
        """
        local_site = self._get_local_site(local_site_name)

        try:
            q = Q(pk=int(repository))
        except ValueError:
            q = (Q(path=repository) | Q(mirror_path=repository)
                 | Q(name=repository))

        repository_qs = (Repository.objects.accessible(
            request.user, local_site=local_site).filter(q))
        repository_count = len(repository_qs)

        if repository_count == 0:
            return INVALID_REPOSITORY, {
                'repository': repository,
            }
        elif repository_count > 1:
            msg = ('Too many repositories matched "%s". Try specifying the '
                   'repository by name instead.' % repository)

            return INVALID_REPOSITORY.with_message(msg), {
                'repository': repository,
            }

        repository = repository_qs.first()

        if not repository.scmtool_class.supports_history:
            return INVALID_ATTRIBUTE, {
                'reason':
                ('The "%s" repository does not support review requests '
                 'created with history.' % repository.name),
            }

        form = ValidateCommitForm(repository=repository,
                                  request=request,
                                  data=request.POST,
                                  files=request.FILES)

        if not form.is_valid():
            return INVALID_FORM_DATA, {
                'fields': self._get_form_errors(form),
            }

        try:
            filediffs = form.validate_diff()
        except FileNotFoundError as e:
            return REPO_FILE_NOT_FOUND, {
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except EmptyDiffError:
            return DIFF_EMPTY
        except DiffTooBigError as e:
            return DIFF_TOO_BIG, {
                'reason': six.text_type(e),
                'max_size': e.max_diff_size,
            }
        except DiffParserError as e:
            return DIFF_PARSE_ERROR, {
                'reason': six.text_type(e),
                'linenum': e.linenum,
            }
        except ShortSHA1Error as e:
            return REPO_FILE_NOT_FOUND, {
                'reason': six.text_type(e),
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except SCMError as e:
            return DIFF_PARSE_ERROR.with_message(six.text_type(e))
        except Exception as e:
            logger.exception(
                'Unexpected exception occurred while validating commit "%s" '
                'in repository "%s" (id %d) with base_commit_id="%s"',
                commit_id,
                repository.name,
                repository.pk,
                base_commit_id,
                request=request)
            return DIFF_PARSE_ERROR.with_message(
                'Unexpected error while validating the diff: %s' % e)

        validation_info = update_validation_info(
            form.cleaned_data.get('validation_info', {}), commit_id, parent_id,
            filediffs)

        return 200, {
            self.item_result_key: {
                'validation_info': serialize_validation_info(validation_info),
            }
        }
예제 #4
0
    def create(self, request, repository, commit_id, parent_id,
               base_commit_id=None, local_site_name=None, *args, **kwargs):
        """Validate a diff for a commit.

        This API has a similar signature to the :ref:`Draft DiffCommit resource
        <webapi2.0-draft-diff-commit-list-resource>` POST API, but instead of
        actually creating commits, it will return a result representing whether
        or not the included diff file parsed and validated correctly.

        This API must be called before posting to the :ref:`Draft DiffCommit
        resource <webapi2.0-draft-diff-commit-list-resource>` because the
        ``validation_info`` field returned by this resource is required for
        posting to that resource.
        """
        local_site = self._get_local_site(local_site_name)

        try:
            q = Q(pk=int(repository))
        except ValueError:
            q = (Q(path=repository) |
                 Q(mirror_path=repository) |
                 Q(name=repository))

        repository_qs = (
            Repository.objects
            .accessible(request.user, local_site=local_site)
            .filter(q)
        )
        repository_count = len(repository_qs)

        if repository_count == 0:
            return INVALID_REPOSITORY, {
                'repository': repository,
            }
        elif repository_count > 1:
            msg = (
                'Too many repositories matched "%s". Try specifying the '
                'repository by name instead.'
                % repository
            )

            return INVALID_REPOSITORY.with_message(msg), {
                'repository': repository,
            }

        repository = repository_qs.first()

        if not repository.scmtool_class.supports_history:
            return INVALID_ATTRIBUTE, {
                'reason': (
                    'The "%s" repository does not support review requests '
                    'created with history.'
                    % repository.name
                ),
            }

        form = ValidateCommitForm(repository=repository,
                                  request=request,
                                  data=request.POST,
                                  files=request.FILES)

        if not form.is_valid():
            return INVALID_FORM_DATA, {
                'fields': self._get_form_errors(form),
            }

        try:
            filediffs = form.validate_diff()
        except FileNotFoundError as e:
            return REPO_FILE_NOT_FOUND, {
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except EmptyDiffError:
            return DIFF_EMPTY
        except DiffTooBigError as e:
            return DIFF_TOO_BIG, {
                'reason': six.text_type(e),
                'max_size': e.max_diff_size,
            }
        except DiffParserError as e:
            return DIFF_PARSE_ERROR, {
                'reason': six.text_type(e),
                'linenum': e.linenum,
            }
        except ShortSHA1Error as e:
            return REPO_FILE_NOT_FOUND, {
                'reason': six.text_type(e),
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except SCMError as e:
            return DIFF_PARSE_ERROR.with_message(six.text_type(e))
        except Exception as e:
            logger.exception(
                'Unexpected exception occurred while validating commit "%s" '
                'in repository "%s" (id %d) with base_commit_id="%s"',
                commit_id,
                repository.name,
                repository.pk,
                base_commit_id,
                request=request)
            return DIFF_PARSE_ERROR.with_message(
                'Unexpected error while validating the diff: %s' % e)

        validation_info = update_validation_info(
            form.cleaned_data.get('validation_info', {}),
            commit_id,
            parent_id,
            filediffs)

        return 200, {
            self.item_result_key: {
                'validation_info': serialize_validation_info(
                    validation_info),
            }
        }