def test_create_filediffs_commit_file_count(self):
        """Testing create_filediffs() with a DiffSet and a DiffCommit"""
        repository = self.create_repository()
        diffset = DiffSet.objects.create_empty(repository=repository)
        commits = [
            DiffCommit.objects.create(
                diffset=diffset,
                filename='diff',
                author_name='Author Name',
                author_email='*****@*****.**',
                commit_message='Message',
                author_date=now(),
                commit_id='a' * 40,
                parent_id='0' * 40),
            DiffCommit.objects.create(
                diffset=diffset,
                filename='diff',
                author_name='Author Name',
                author_email='*****@*****.**',
                commit_message='Message',
                author_date=now(),
                commit_id='b' * 40,
                parent_id='a' * 40),
        ]

        self.assertEqual(diffset.files.count(), 0)
        self.assertEqual(commits[0].files.count(), 0)

        create_filediffs(
            self.DEFAULT_GIT_FILEDIFF_DATA_DIFF,
            None,
            repository=repository,
            basedir='/',
            base_commit_id='0' * 40,
            diffset=diffset,
            diffcommit=commits[0],
            check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)
        commits[0] = DiffCommit.objects.get(pk=commits[0].pk)

        self.assertEqual(diffset.files.count(), 1)
        self.assertEqual(commits[0].files.count(), 1)

        create_filediffs(
            self.DEFAULT_GIT_FILEDIFF_DATA_DIFF,
            None,
            repository=repository,
            basedir='/',
            base_commit_id='0' * 40,
            diffset=diffset,
            diffcommit=commits[1],
            check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)
        commits[1] = DiffCommit.objects.get(pk=commits[1].pk)

        self.assertEqual(diffset.files.count(), 2)
        self.assertEqual(commits[1].files.count(), 1)
    def test_create_filediffs_commit_file_count(self):
        """Testing create_filediffs() with a DiffSet and a DiffCommit"""
        repository = self.create_repository()
        diffset = DiffSet.objects.create_empty(repository=repository)
        commits = [
            DiffCommit.objects.create(diffset=diffset,
                                      filename='diff',
                                      author_name='Author Name',
                                      author_email='*****@*****.**',
                                      commit_message='Message',
                                      author_date=now(),
                                      commit_id='a' * 40,
                                      parent_id='0' * 40),
            DiffCommit.objects.create(diffset=diffset,
                                      filename='diff',
                                      author_name='Author Name',
                                      author_email='*****@*****.**',
                                      commit_message='Message',
                                      author_date=now(),
                                      commit_id='b' * 40,
                                      parent_id='a' * 40),
        ]

        self.assertEqual(diffset.file_count, 0)
        self.assertEqual(commits[0].file_count, 0)

        create_filediffs(self.DEFAULT_GIT_FILEDIFF_DATA,
                         None,
                         repository=repository,
                         basedir='/',
                         base_commit_id='0' * 40,
                         diffset=diffset,
                         diffcommit=commits[0],
                         check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)
        commits[0] = DiffCommit.objects.get(pk=commits[0].pk)

        self.assertEqual(len(diffset.files.all()), 1)
        self.assertEqual(diffset.file_count, 1)
        self.assertEqual(len(commits[0].files.all()), 1)
        self.assertEqual(commits[0].file_count, 1)

        create_filediffs(self.DEFAULT_GIT_FILEDIFF_DATA,
                         None,
                         repository=repository,
                         basedir='/',
                         base_commit_id='0' * 40,
                         diffset=diffset,
                         diffcommit=commits[1],
                         check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)
        commits[1] = DiffCommit.objects.get(pk=commits[1].pk)

        self.assertEqual(len(diffset.files.all()), 2)
        self.assertEqual(diffset.file_count, 2)
        self.assertEqual(len(commits[1].files.all()), 1)
        self.assertEqual(commits[1].file_count, 1)
    def test_create_filediffs_file_count(self):
        """Testing create_filediffs() with a DiffSet"""
        repository = self.create_repository()
        diffset = self.create_diffset(repository=repository)

        self.assertEqual(diffset.files.count(), 0)

        create_filediffs(self.DEFAULT_GIT_FILEDIFF_DATA_DIFF,
                         None,
                         repository=repository,
                         basedir='/',
                         base_commit_id='0' * 40,
                         diffset=diffset,
                         check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)

        self.assertEqual(diffset.files.count(), 1)
    def test_create_filediffs_file_count(self):
        """Testing create_filediffs() with a DiffSet"""
        repository = self.create_repository()
        diffset = self.create_diffset(repository=repository)

        self.assertEqual(diffset.files.count(), 0)

        create_filediffs(
            self.DEFAULT_GIT_FILEDIFF_DATA_DIFF,
            None,
            repository=repository,
            basedir='/',
            base_commit_id='0' * 40,
            diffset=diffset,
            check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)

        self.assertEqual(diffset.files.count(), 1)
    def test_create_filediffs_with_symlinks_and_targets(self):
        """Testing create_filediffs() with symlinks and symlink targets"""
        repository = self.create_repository(tool_name='TestToolDiffX')
        diffset = self.create_diffset(repository=repository)

        self.assertEqual(diffset.files.count(), 0)

        create_filediffs(
            diff_file_contents=(
                b'#diffx: encoding=utf-8, version=1.0\n'
                b'#.change:\n'
                b'#..file:\n'
                b'#...meta: format=json, length=230\n'
                b'{\n'
                b'    "op": "modify",\n'
                b'    "path": "name",\n'
                b'    "revision": {\n'
                b'        "old": "abc123",\n'
                b'        "new": "def456"\n'
                b'    },\n'
                b'    "symlink target": {\n'
                b'        "old": "old/target/",\n'
                b'        "new": "new/target/"\n'
                b'    },\n'
                b'    "type": "symlink"\n'
                b'}\n'
            ),
            parent_diff_file_contents=None,
            repository=repository,
            basedir='/',
            base_commit_id='0' * 40,
            diffset=diffset,
            check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)

        self.assertEqual(diffset.files.count(), 1)
        filediff = diffset.files.get()

        self.assertTrue(filediff.is_symlink)
        self.assertEqual(filediff.old_symlink_target, 'old/target/')
        self.assertEqual(filediff.new_symlink_target, 'new/target/')
    def test_create_filediffs_with_unix_mode(self):
        """Testing create_filediffs() with UNIX file modes"""
        repository = self.create_repository(tool_name='TestToolDiffX')
        diffset = self.create_diffset(repository=repository)

        self.assertEqual(diffset.files.count(), 0)

        create_filediffs(
            diff_file_contents=(
                b'#diffx: encoding=utf-8, version=1.0\n'
                b'#.change:\n'
                b'#..file:\n'
                b'#...meta: format=json, length=199\n'
                b'{\n'
                b'    "op": "modify",\n'
                b'    "path": "name",\n'
                b'    "revision": {\n'
                b'        "old": "abc123",\n'
                b'        "new": "def456"\n'
                b'    },\n'
                b'    "unix file mode": {\n'
                b'        "old": "0100644",\n'
                b'        "new": "0100755"\n'
                b'    }\n'
                b'}\n'
            ),
            parent_diff_file_contents=None,
            repository=repository,
            basedir='/',
            base_commit_id='0' * 40,
            diffset=diffset,
            check_existence=False)

        diffset = DiffSet.objects.get(pk=diffset.pk)

        self.assertEqual(diffset.files.count(), 1)
        filediff = diffset.files.get()

        self.assertEqual(filediff.old_unix_mode, '0100644')
        self.assertEqual(filediff.new_unix_mode, '0100755')
Example #7
0
    def create_from_data(self,
                         repository,
                         diff_file_name,
                         diff_file_contents,
                         parent_diff_file_name=None,
                         parent_diff_file_contents=None,
                         diffset_history=None,
                         basedir=None,
                         request=None,
                         base_commit_id=None,
                         check_existence=True,
                         validate_only=False,
                         **kwargs):
        """Create a DiffSet from raw diff data.

        This parses a diff and optional parent diff covering one or more files,
        validates, and constructs :py:class:`DiffSets
        <reviewboard.diffviewer.models.diffset.DiffSet>` and
        :py:class:`FileDiffs <reviewboard.diffviewer.models.filediff.FileDiff>`
        representing the diff.

        This can optionally validate the diff without saving anything to the
        database. In this case, no value will be returned. Instead, callers
        should take any result as success.

        Args:
            repository (reviewboard.scmtools.models.Repository):
                The repository the diff applies to.

            diff_file_name (unicode):
                The filename of the main diff file.

            diff_file_contents (bytes):
                The contents of the main diff file.

            parent_diff_file_name (unicode, optional):
                The filename of the parent diff, if one is provided.

            parent_diff_file_contents (bytes, optional):
                The contents of the parent diff, if one is provided.

            diffset_history (reviewboard.diffviewer.models.diffset_history.
                             DiffSetHistory, optional):
                The history object to associate the DiffSet with. This is
                not required if using ``validate_only=True``.

            basedir (unicode, optional):
                The base directory to prepend to all file paths in the diff.

            request (django.http.HttpRequest, optional):
                The current HTTP request, if any. This will result in better
                logging.

            base_commit_id (unicode, optional):
                The ID of the commit that the diff is based upon. This is
                needed by some SCMs or hosting services to properly look up
                files, if the diffs represent blob IDs instead of commit IDs
                and the service doesn't support those lookups.

            check_existence (bool, optional):
                Whether to check for file existence as part of the validation
                process. This defaults to ``True``.

            validate_only (bool, optional):
                Whether to just validate and not save. If ``True``, then this
                won't populate the database at all and will return ``None``
                upon success. This defaults to ``False``.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            reviewboard.diffviewer.models.diffset.DiffSet:
            The resulting DiffSet stored in the database, if processing
            succeeded and ``validate_only=False``.

        Raises:
            reviewboard.diffviewer.errors.DiffParserError:
                There was an error parsing the main diff or parent diff.

            reviewboard.diffviewer.errors.EmptyDiffError:
                The provided diff file did not contain any file changes.

            reviewboard.scmtools.core.FileNotFoundError:
                A file specified in the diff could not be found in the
                repository.

            reviewboard.scmtools.core.SCMError:
                There was an error talking to the repository when validating
                the existence of a file.

            reviewboard.scmtools.git.ShortSHA1Error:
                A SHA1 specified in the diff was in the short form, which
                could not be used to look up the file. This is applicable only
                to Git.
        """
        if 'save' in kwargs:
            warnings.warn(
                'The save parameter to '
                'DiffSet.objects.create_from_data is deprecated. '
                'Please set validate_only instead.',
                RemovedInReviewBoard40Warning)
            validate_only = not kwargs['save']

        diffset = self.model(name=diff_file_name,
                             revision=0,
                             basedir=basedir,
                             history=diffset_history,
                             repository=repository,
                             diffcompat=DiffCompatVersion.DEFAULT,
                             base_commit_id=base_commit_id)

        if not validate_only:
            diffset.save()

        create_filediffs(get_file_exists=repository.get_file_exists,
                         diff_file_contents=diff_file_contents,
                         parent_diff_file_contents=parent_diff_file_contents,
                         repository=repository,
                         request=request,
                         basedir=basedir,
                         base_commit_id=base_commit_id,
                         diffset=diffset,
                         check_existence=check_existence,
                         validate_only=validate_only)

        if validate_only:
            return None

        return diffset
Example #8
0
    def create_from_data(self,
                         repository,
                         diff_file_name,
                         diff_file_contents,
                         parent_diff_file_name,
                         parent_diff_file_contents,
                         diffset,
                         commit_id,
                         parent_id,
                         commit_message,
                         author_name,
                         author_email,
                         author_date,
                         validation_info=None,
                         request=None,
                         committer_name=None,
                         committer_email=None,
                         committer_date=None,
                         base_commit_id=None,
                         check_existence=True,
                         validate_only=False):
        """Create a DiffCommit from raw diff data.

        Args:
            repository (reviewboard.scmtools.models.Repository):
                The repository the diff was posted against.

            diff_file_name (unicode):
                The name of the diff file.

            diff_file_contents (bytes):
                The contents of the diff file.

            parent_diff_file_name (unicode):
                The name of the parent diff file.

            parent_diff_file_contents (bytes):
                The contents of the parent diff file.

            diffset (reviewboard.diffviewer.models.diffset.DiffSet):
                The DiffSet to attach the created DiffCommit to.

            commit_id (unicode):
                The unique identifier of the commit.

            parent_id (unicode):
                The unique identifier of the parent commit.

            commit_message (unicode):
                The commit message.

            author_name (unicode):
                The author's name.

            author_email (unicode):
                The author's e-mail address.

            author_date (datetime.datetime):
                The date and time that the commit was authored.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            validation_info (dict, optional):
                A dictionary of parsed validation information from the
                :py:class:`~reviewboard.webapi.resources.validate_diffcommit.
                ValidateDiffCommitResource`.

            committer_name (unicode, optional):
                The committer's name.

            committer_email (unicode, optional)
                The committer's e-mail address.

            committer_date (datetime.datetime, optional):
                The date and time that the commit was committed.

            base_commit_id (unicode, optional):
                The ID of the commit that the diff is based upon. This is
                needed by some SCMs or hosting services to properly look up
                files, if the diffs represent blob IDs instead of commit IDs
                and the service doesn't support those lookups.

            check_existence (bool, optional):
                Whether or not existence checks should be performed against
                the upstream repository.

            validate_only (bool, optional):
                Whether to just validate and not save. If ``True``, then this
                won't populate the database at all and will return ``None``
                upon success. This defaults to ``False``.

        Returns:
            reviewboard.diffviewer.models.diffcommit.DiffCommit:
            The created model instance.
        """
        diffcommit = self.model(filename=diff_file_name,
                                diffset=diffset,
                                commit_id=commit_id,
                                parent_id=parent_id,
                                author_name=author_name,
                                author_email=author_email,
                                author_date=author_date,
                                commit_message=commit_message,
                                committer_name=committer_name,
                                committer_email=committer_email,
                                committer_date=committer_date)

        if not validate_only:
            diffcommit.save()

        get_file_exists = partial(get_file_exists_in_history, validation_info
                                  or {}, repository, parent_id)

        create_filediffs(get_file_exists=get_file_exists,
                         diff_file_contents=diff_file_contents,
                         parent_diff_file_contents=parent_diff_file_contents,
                         repository=repository,
                         request=request,
                         basedir='',
                         base_commit_id=base_commit_id,
                         diffset=diffset,
                         diffcommit=diffcommit,
                         validate_only=validate_only,
                         check_existence=check_existence)

        if validate_only:
            return None

        return diffcommit
Example #9
0
    def finalize_commit_series(self, cumulative_diff, validation_info,
                               parent_diff=None, request=None, validate=True,
                               save=False):
        """Finalize the commit series represented by this DiffSet.

        Args:
            cumulative_diff (bytes):
                The cumulative diff of the entire commit series.

            validation_info (dict):
                The parsed validation information.

            parent_diff (bytes, optional):
                The parent diff of the cumulative diff, if any.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client, if any.

            validate (bool, optional):
                Whether or not the cumulative diff (and optional parent diff)
                should be validated, up to and including file existence checks.

            save (bool, optional):
                Whether to save the model after finalization. Defaults to
                ``False``.

                If ``True``, only the :py:attr:`extra_data` field will be
                updated.

                If ``False``, the caller must save this model.

        Returns:
            list of reviewboard.diffviewer.models.filediff.FileDiff:
            The list of created FileDiffs.

        Raises:
            django.core.exceptions.ValidationError:
                The commit series failed validation.
        """
        if validate:
            if self.is_commit_series_finalized:
                raise ValidationError(
                    ugettext('This diff is already finalized.'),
                    code='invalid')

            if not self.files.exists():
                raise ValidationError(
                    ugettext('Cannot finalize an empty commit series.'),
                    code='invalid')

            commits = {
                commit.commit_id: commit
                for commit in self.commits.all()
            }

            missing_commit_ids = set()

            for commit_id, info in six.iteritems(validation_info):
                if (commit_id not in commits or
                    commits[commit_id].parent_id != info['parent_id']):
                    missing_commit_ids.add(commit_id)

            if missing_commit_ids:
                raise ValidationError(
                    ugettext('The following commits are specified in '
                             'validation_info but do not exist: %s')
                    % ', '.join(missing_commit_ids),
                    code='validation_info')

            for commit_id, commit in six.iteritems(commits):
                if (commit_id not in validation_info or
                    validation_info[commit_id]['parent_id'] !=
                        commit.parent_id):
                    missing_commit_ids.add(commit_id)

            if missing_commit_ids:
                raise ValidationError(
                    ugettext('The following commits exist but are not '
                             'present in validation_info: %s')
                    % ', '.join(missing_commit_ids),
                    code='validation_info')

        filediffs = create_filediffs(
            get_file_exists=self.repository.get_file_exists,
            diff_file_contents=cumulative_diff,
            parent_diff_file_contents=parent_diff,
            repository=self.repository,
            request=request,
            basedir=self.basedir,
            base_commit_id=self.base_commit_id,
            diffset=self,
            check_existence=validate)

        if self.extra_data is None:
            self.extra_data = {}

        self.extra_data[self._FINALIZED_COMMIT_SERIES_KEY] = True

        if save:
            self.save(update_fields=('extra_data',))

        return filediffs
Example #10
0
    def validate_diff(self):
        """Validate the DiffCommit.

        This will attempt to parse the given diff (and optionally parent
        diff) into :py:class:`FileDiffs
        <reviewboard.diffviewer.models.filediff.FileDiff>`. This will not
        result in anything being committed to the database.

        Returns:
            tuple:
            A 2-tuple containing the following:

            * A list of the created FileDiffs.
            * A list of the parent FileDiffs, or ``None``.

        Raises:
            reviewboard.diffviewer.errors.DiffParserError:
                The diff could not be parsed.

            reviewboard.diffviewer.errors.DiffTooBigError:
                The diff was too big.

            reviewboard.diffviewer.errors.EmptyDiffError:
                The diff did not contain any changes.

            reviewboard.scmtools.errors.FileNotFoundError:
                A file was not found in the repository.

            reviewboard.scmtools.errors.SCMError:
                An error occurred within the SCMTool.
        """
        assert self.is_valid()

        diff_file = self.cleaned_data['diff']
        parent_diff_file = self.cleaned_data.get('parent_diff')
        validation_info = self.cleaned_data.get('validation_info')

        check_diff_size(diff_file, parent_diff_file)

        if parent_diff_file:
            parent_diff_file_contents = parent_diff_file.read()
        else:
            parent_diff_file_contents = None

        base_commit_id = self.cleaned_data['base_commit_id']

        diffset = DiffSet(name='diff',
                          revision=0,
                          basedir='',
                          repository=self.repository,
                          diffcompat=DiffCompatVersion.DEFAULT,
                          base_commit_id=base_commit_id)

        get_file_exists = partial(get_file_exists_in_history,
                                  validation_info or {},
                                  self.repository,
                                  self.cleaned_data['parent_id'])

        return create_filediffs(
            diff_file_contents=diff_file.read(),
            parent_diff_file_contents=parent_diff_file_contents,
            repository=self.repository,
            basedir='',
            base_commit_id=base_commit_id,
            get_file_exists=get_file_exists,
            diffset=diffset,
            request=self.request,
            diffcommit=None,
            validate_only=True)
Example #11
0
    def validate_diff(self):
        """Validate the DiffCommit.

        This will attempt to parse the given diff (and optionally parent
        diff) into :py:class:`FileDiffs
        <reviewboard.diffviewer.models.filediff.FileDiff>`. This will not
        result in anything being committed to the database.

        Returns:
            tuple:
            A 2-tuple containing the following:

            * A list of the created FileDiffs.
            * A list of the parent FileDiffs, or ``None``.

        Raises:
            reviewboard.diffviewer.errors.DiffParserError:
                The diff could not be parsed.

            reviewboard.diffviewer.errors.DiffTooBigError:
                The diff was too big.

            reviewboard.diffviewer.errors.EmptyDiffError:
                The diff did not contain any changes.

            reviewboard.scmtools.errors.FileNotFoundError:
                A file was not found in the repository.

            reviewboard.scmtools.errors.SCMError:
                An error occurred within the SCMTool.
        """
        assert self.is_valid()

        diff_file = self.cleaned_data['diff']
        parent_diff_file = self.cleaned_data.get('parent_diff')
        validation_info = self.cleaned_data.get('validation_info')

        check_diff_size(diff_file, parent_diff_file)

        if parent_diff_file:
            parent_diff_file_contents = parent_diff_file.read()
        else:
            parent_diff_file_contents = None

        base_commit_id = self.cleaned_data['base_commit_id']

        diffset = DiffSet(name='diff',
                          revision=0,
                          basedir='',
                          repository=self.repository,
                          diffcompat=DiffCompatVersion.DEFAULT,
                          base_commit_id=base_commit_id)

        get_file_exists = partial(get_file_exists_in_history, validation_info
                                  or {}, self.repository,
                                  self.cleaned_data['parent_id'])

        return create_filediffs(
            diff_file_contents=diff_file.read(),
            parent_diff_file_contents=parent_diff_file_contents,
            repository=self.repository,
            basedir='',
            base_commit_id=base_commit_id,
            get_file_exists=get_file_exists,
            diffset=diffset,
            request=self.request,
            diffcommit=None,
            validate_only=True)
Example #12
0
    def finalize_commit_series(self,
                               cumulative_diff,
                               validation_info,
                               parent_diff=None,
                               request=None,
                               validate=True,
                               save=False):
        """Finalize the commit series represented by this DiffSet.

        Args:
            cumulative_diff (bytes):
                The cumulative diff of the entire commit series.

            validation_info (dict):
                The parsed validation information.

            parent_diff (bytes, optional):
                The parent diff of the cumulative diff, if any.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client, if any.

            validate (bool, optional):
                Whether or not the cumulative diff (and optional parent diff)
                should be validated, up to and including file existence checks.

            save (bool, optional):
                Whether to save the model after finalization. Defaults to
                ``False``.

                If ``True``, only the :py:attr:`extra_data` field will be
                updated.

                If ``False``, the caller must save this model.

        Returns:
            list of reviewboard.diffviewer.models.filediff.FileDiff:
            The list of created FileDiffs.

        Raises:
            django.core.exceptions.ValidationError:
                The commit series failed validation.
        """
        if validate:
            if self.is_commit_series_finalized:
                raise ValidationError(
                    ugettext('This diff is already finalized.'),
                    code='invalid')

            if not self.files.exists():
                raise ValidationError(
                    ugettext('Cannot finalize an empty commit series.'),
                    code='invalid')

            commits = {
                commit.commit_id: commit
                for commit in self.commits.all()
            }

            missing_commit_ids = set()

            for commit_id, info in six.iteritems(validation_info):
                if (commit_id not in commits
                        or commits[commit_id].parent_id != info['parent_id']):
                    missing_commit_ids.add(commit_id)

            if missing_commit_ids:
                raise ValidationError(
                    ugettext('The following commits are specified in '
                             'validation_info but do not exist: %s') %
                    ', '.join(missing_commit_ids),
                    code='validation_info')

            for commit_id, commit in six.iteritems(commits):
                if (commit_id not in validation_info
                        or validation_info[commit_id]['parent_id'] !=
                        commit.parent_id):
                    missing_commit_ids.add(commit_id)

            if missing_commit_ids:
                raise ValidationError(
                    ugettext('The following commits exist but are not '
                             'present in validation_info: %s') %
                    ', '.join(missing_commit_ids),
                    code='validation_info')

        filediffs = create_filediffs(
            get_file_exists=self.repository.get_file_exists,
            diff_file_contents=cumulative_diff,
            parent_diff_file_contents=parent_diff,
            repository=self.repository,
            request=request,
            basedir=self.basedir,
            base_commit_id=self.base_commit_id,
            diffset=self,
            check_existence=validate)

        if self.extra_data is None:
            self.extra_data = {}

        self.extra_data[self._FINALIZED_COMMIT_SERIES_KEY] = True

        if save:
            self.save(update_fields=('extra_data', ))

        return filediffs
Example #13
0
    def create_from_data(self,
                         repository,
                         diff_file_name,
                         diff_file_contents,
                         parent_diff_file_name=None,
                         parent_diff_file_contents=None,
                         diffset_history=None,
                         basedir=None,
                         request=None,
                         base_commit_id=None,
                         check_existence=True,
                         validate_only=False,
                         **kwargs):
        """Create a DiffSet from raw diff data.

        This parses a diff and optional parent diff covering one or more files,
        validates, and constructs :py:class:`DiffSets
        <reviewboard.diffviewer.models.diffset.DiffSet>` and
        :py:class:`FileDiffs <reviewboard.diffviewer.models.filediff.FileDiff>`
        representing the diff.

        This can optionally validate the diff without saving anything to the
        database. In this case, no value will be returned. Instead, callers
        should take any result as success.

        Args:
            repository (reviewboard.scmtools.models.Repository):
                The repository the diff applies to.

            diff_file_name (unicode):
                The filename of the main diff file.

            diff_file_contents (bytes):
                The contents of the main diff file.

            parent_diff_file_name (unicode, optional):
                The filename of the parent diff, if one is provided.

            parent_diff_file_contents (bytes, optional):
                The contents of the parent diff, if one is provided.

            diffset_history (reviewboard.diffviewer.models.diffset_history.
                             DiffSetHistory, optional):
                The history object to associate the DiffSet with. This is
                not required if using ``validate_only=True``.

            basedir (unicode, optional):
                The base directory to prepend to all file paths in the diff.

            request (django.http.HttpRequest, optional):
                The current HTTP request, if any. This will result in better
                logging.

            base_commit_id (unicode, optional):
                The ID of the commit that the diff is based upon. This is
                needed by some SCMs or hosting services to properly look up
                files, if the diffs represent blob IDs instead of commit IDs
                and the service doesn't support those lookups.

            check_existence (bool, optional):
                Whether to check for file existence as part of the validation
                process. This defaults to ``True``.

            validate_only (bool, optional):
                Whether to just validate and not save. If ``True``, then this
                won't populate the database at all and will return ``None``
                upon success. This defaults to ``False``.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            reviewboard.diffviewer.models.diffset.DiffSet:
            The resulting DiffSet stored in the database, if processing
            succeeded and ``validate_only=False``.

        Raises:
            reviewboard.diffviewer.errors.DiffParserError:
                There was an error parsing the main diff or parent diff.

            reviewboard.diffviewer.errors.EmptyDiffError:
                The provided diff file did not contain any file changes.

            reviewboard.scmtools.core.FileNotFoundError:
                A file specified in the diff could not be found in the
                repository.

            reviewboard.scmtools.core.SCMError:
                There was an error talking to the repository when validating
                the existence of a file.

            reviewboard.scmtools.git.ShortSHA1Error:
                A SHA1 specified in the diff was in the short form, which
                could not be used to look up the file. This is applicable only
                to Git.
        """
        if 'save' in kwargs:
            warnings.warn('The save parameter to '
                          'DiffSet.objects.create_from_data is deprecated. '
                          'Please set validate_only instead.',
                          RemovedInReviewBoard40Warning)
            validate_only = not kwargs['save']

        diffset = self.model(
            name=diff_file_name,
            revision=0,
            basedir=basedir,
            history=diffset_history,
            repository=repository,
            diffcompat=DiffCompatVersion.DEFAULT,
            base_commit_id=base_commit_id)

        if not validate_only:
            diffset.save()

        create_filediffs(
            get_file_exists=repository.get_file_exists,
            diff_file_contents=diff_file_contents,
            parent_diff_file_contents=parent_diff_file_contents,
            repository=repository,
            request=request,
            basedir=basedir,
            base_commit_id=base_commit_id,
            diffset=diffset,
            check_existence=check_existence,
            validate_only=validate_only
        )

        if validate_only:
            return None

        return diffset
Example #14
0
    def create_from_data(self,
                         repository,
                         diff_file_name,
                         diff_file_contents,
                         parent_diff_file_name,
                         parent_diff_file_contents,
                         diffset,
                         commit_id,
                         parent_id,
                         commit_message,
                         author_name,
                         author_email,
                         author_date,
                         validation_info=None,
                         request=None,
                         committer_name=None,
                         committer_email=None,
                         committer_date=None,
                         base_commit_id=None,
                         check_existence=True,
                         validate_only=False):
        """Create a DiffCommit from raw diff data.

        Args:
            repository (reviewboard.scmtools.models.Repository):
                The repository the diff was posted against.

            diff_file_name (unicode):
                The name of the diff file.

            diff_file_contents (bytes):
                The contents of the diff file.

            parent_diff_file_name (unicode):
                The name of the parent diff file.

            parent_diff_file_contents (bytes):
                The contents of the parent diff file.

            diffset (reviewboard.diffviewer.models.diffset.DiffSet):
                The DiffSet to attach the created DiffCommit to.

            commit_id (unicode):
                The unique identifier of the commit.

            parent_id (unicode):
                The unique identifier of the parent commit.

            commit_message (unicode):
                The commit message.

            author_name (unicode):
                The author's name.

            author_email (unicode):
                The author's e-mail address.

            author_date (datetime.datetime):
                The date and time that the commit was authored.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            validation_info (dict, optional):
                A dictionary of parsed validation information from the
                :py:class:`~reviewboard.webapi.resources.validate_diffcommit.
                ValidateDiffCommitResource`.

            committer_name (unicode, optional):
                The committer's name.

            committer_email (unicode, optional)
                The committer's e-mail address.

            committer_date (datetime.datetime, optional):
                The date and time that the commit was committed.

            base_commit_id (unicode, optional):
                The ID of the commit that the diff is based upon. This is
                needed by some SCMs or hosting services to properly look up
                files, if the diffs represent blob IDs instead of commit IDs
                and the service doesn't support those lookups.

            check_existence (bool, optional):
                Whether or not existence checks should be performed against
                the upstream repository.

            validate_only (bool, optional):
                Whether to just validate and not save. If ``True``, then this
                won't populate the database at all and will return ``None``
                upon success. This defaults to ``False``.

        Returns:
            reviewboard.diffviewer.models.diffcommit.DiffCommit:
            The created model instance.
        """
        diffcommit = self.model(
            filename=diff_file_name,
            diffset=diffset,
            commit_id=commit_id,
            parent_id=parent_id,
            author_name=author_name,
            author_email=author_email,
            author_date=author_date,
            commit_message=commit_message,
            committer_name=committer_name,
            committer_email=committer_email,
            committer_date=committer_date)

        if not validate_only:
            diffcommit.save()

        get_file_exists = partial(get_file_exists_in_history,
                                  validation_info or {},
                                  repository,
                                  parent_id)

        create_filediffs(
            get_file_exists=get_file_exists,
            diff_file_contents=diff_file_contents,
            parent_diff_file_contents=parent_diff_file_contents,
            repository=repository,
            request=request,
            basedir='',
            base_commit_id=base_commit_id,
            diffset=diffset,
            diffcommit=diffcommit,
            validate_only=validate_only,
            check_existence=check_existence)

        if validate_only:
            return None

        return diffcommit