Title: [274542] trunk/Tools
Revision
274542
Author
jbed...@apple.com
Date
2021-03-16 17:53:41 -0700 (Tue, 16 Mar 2021)

Log Message

[resultsdbpy] Save identifiers in commit table
https://bugs.webkit.org/show_bug.cgi?id=223101
<rdar://problem/75338338>

Reviewed by Dewei Zhu.

* Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py: Bump version.
* Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py:
(CommitController.register): Accept uploaded new commit objects, continue to return old-style commits.
* Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py:
(UploadController.upload): Register commits using the fast path when uploading results.
* Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller_unittest.py:
(UploadControllerTest.test_process): Mock safari and WebKit when processing results.
(UploadControllerTest.test_process_commit): Ditto.
* Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context.py:
(CommitContext.CommitModelMk2): Add new style commit model base.
(CommitContext.CommitByRef): Sort commits by hash, revision and identifier references.
(CommitContext.CommitByUuidAscendingMk2): New commit style UUID table.
(CommitContext.CommitByUuidDescendingMk2): Ditto.
(CommitContext.__init__): Create new tables.
(CommitContext.find_commits_by_ref): Search for commits in the new ref table.
(CommitContext.register): Post-process commits to populate identifier field.
(CommitContext.register_commit): Only register new-style commits.
(CommitContext.register_partial_commit): Register new-style commits, allow caller to opt-out of expensive
Identifier computation.
(CommitContext.url): Accept old and new style commits.
(CommitContext.register_commit_with_repo_and_id): Deleted.
* Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context_unittest.py:
(CommitContextTest.add_all_commits_to_database): Update commit registration call.
(CommitContextTest.test_commit_from_stash_repo): Ditto.
(CommitContextTest.test_commit_from_svn_repo): Ditto.
* Scripts/libraries/resultsdbpy/resultsdbpy/model/mock_model_factory.py:
(MockModelFactory.create): Update commit registration call.
* Scripts/libraries/resultsdbpy/resultsdbpy/model/model.py:
(Model.__init__): commit_context may now post-process uploads.
* Scripts/libraries/resultsdbpy/resultsdbpy/model/repository.py:
(Repository.commit): Add call to return new-style commits.
(StashRepository.commit): Ditto.
(WebKitRepository.commit): Ditto.
* Scripts/libraries/resultsdbpy/resultsdbpy/model/repository_unittest.py:
(RepositoryTest.test_svn):
(RepositoryTest.test_ref_svn):
(RepositoryTest.test_stash):
(RepositoryTest.test_ref_stash):
(RepositoryTest.test_colliding_timestamps_stash):
(RepositoryTest.test_branch_stash):
(RepositoryTest.test_branch_svn): Deleted.
* Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context_unittest.py:
(UploadContextTest.test_callback):
(UploadContextTest.test_async_callback):
* Scripts/libraries/resultsdbpy/setup.py: Bump version.
* Scripts/libraries/webkitscmpy/webkitscmpy/commit.py:
(Commit): Handle single email passed to contributor.

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (274541 => 274542)


--- trunk/Tools/ChangeLog	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/ChangeLog	2021-03-17 00:53:41 UTC (rev 274542)
@@ -1,5 +1,61 @@
 2021-03-16  Jonathan Bedard  <jbed...@apple.com>
 
+        [resultsdbpy] Save identifiers in commit table
+        https://bugs.webkit.org/show_bug.cgi?id=223101
+        <rdar://problem/75338338>
+
+        Reviewed by Dewei Zhu.
+
+        * Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py: Bump version.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py:
+        (CommitController.register): Accept uploaded new commit objects, continue to return old-style commits.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py:
+        (UploadController.upload): Register commits using the fast path when uploading results.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller_unittest.py:
+        (UploadControllerTest.test_process): Mock safari and WebKit when processing results.
+        (UploadControllerTest.test_process_commit): Ditto.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context.py:
+        (CommitContext.CommitModelMk2): Add new style commit model base.
+        (CommitContext.CommitByRef): Sort commits by hash, revision and identifier references.
+        (CommitContext.CommitByUuidAscendingMk2): New commit style UUID table.
+        (CommitContext.CommitByUuidDescendingMk2): Ditto.
+        (CommitContext.__init__): Create new tables.
+        (CommitContext.find_commits_by_ref): Search for commits in the new ref table.
+        (CommitContext.register): Post-process commits to populate identifier field.
+        (CommitContext.register_commit): Only register new-style commits.
+        (CommitContext.register_partial_commit): Register new-style commits, allow caller to opt-out of expensive
+        Identifier computation.
+        (CommitContext.url): Accept old and new style commits.
+        (CommitContext.register_commit_with_repo_and_id): Deleted.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context_unittest.py:
+        (CommitContextTest.add_all_commits_to_database): Update commit registration call.
+        (CommitContextTest.test_commit_from_stash_repo): Ditto.
+        (CommitContextTest.test_commit_from_svn_repo): Ditto.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/model/mock_model_factory.py:
+        (MockModelFactory.create): Update commit registration call.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/model/model.py:
+        (Model.__init__): commit_context may now post-process uploads.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/model/repository.py:
+        (Repository.commit): Add call to return new-style commits.
+        (StashRepository.commit): Ditto.
+        (WebKitRepository.commit): Ditto.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/model/repository_unittest.py:
+        (RepositoryTest.test_svn):
+        (RepositoryTest.test_ref_svn):
+        (RepositoryTest.test_stash):
+        (RepositoryTest.test_ref_stash):
+        (RepositoryTest.test_colliding_timestamps_stash):
+        (RepositoryTest.test_branch_stash):
+        (RepositoryTest.test_branch_svn): Deleted.
+        * Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context_unittest.py:
+        (UploadContextTest.test_callback):
+        (UploadContextTest.test_async_callback):
+        * Scripts/libraries/resultsdbpy/setup.py: Bump version.
+        * Scripts/libraries/webkitscmpy/webkitscmpy/commit.py:
+        (Commit): Handle single email passed to contributor.
+
+2021-03-16  Jonathan Bedard  <jbed...@apple.com>
+
         [resultsdbpy] Allow user to change commit representation
         https://bugs.webkit.org/show_bug.cgi?id=223215
         <rdar://problem/75446602>

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -44,6 +44,6 @@
         "Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
     )
 
-version = Version(2, 0, 2)
+version = Version(2, 0, 3)
 
 name = 'resultsdbpy'

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -1,4 +1,4 @@
-# Copyright (C) 2019 Apple Inc. All rights reserved.
+# Copyright (C) 2019-2021 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -26,7 +26,7 @@
 from flask import abort, jsonify, request
 from resultsdbpy.controller.commit import Commit
 from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query
-from webkitscmpy import ScmBase
+from webkitscmpy import ScmBase, Commit as ScmCommit
 
 
 def _find_comparison(commit_context, repository_id, branch, id, uuid, timestamp, priority=min):
@@ -265,7 +265,7 @@
             commit = self.commit_context.previous_commit(commits[0])
             return jsonify(Commit.Encoder().default([commit] if commit else []))
 
-    def register(self, commit=None):
+    def register(self, commit=None, fast=True):
         is_endpoint = not bool(commit)
         if is_endpoint:
             AssertRequest.is_type(['POST'])
@@ -280,31 +280,48 @@
                 abort(400, description='Expected uploaded data to be json')
 
         try:
-            self.commit_context.register_commit(Commit.from_json(commit))
-            if is_endpoint:
-                return jsonify({'status': 'ok'})
-            return Commit.from_json(commit)
+            candidate = ScmCommit.from_json(commit)
+
+            # Commit needs to be sufficiently defined
+            if candidate.repository_id and candidate.branch and candidate.timestamp and (candidate.revision or candidate.hash):
+                self.commit_context.register_commit(candidate)
+                if is_endpoint:
+                    return jsonify({'status': 'ok'})
+                return candidate
         except ValueError:
             pass
 
-        required_args = ['repository_id', 'id']
-        optional_args = ['branch']
+        required_args = ['repository_id']
         for arg in required_args:
             if arg not in commit:
                 abort(400, description=f"'{arg}' required to define commit")
 
+        has_ref = False
+        _one_of_args_ = ['id', 'ref', 'hash', 'revision', 'identifier']
+        for arg in one_of_args:
+            if arg in commit:
+                if has_ref:
+                    abort(400, description='Multiple commit references specified')
+                has_ref = True
+        if not has_ref:
+            abort(400, description='No commit reference specified')
+
+
         for arg in commit.keys():
-            if arg in required_args + optional_args:
+            if arg in required_args or arg in one_of_args:
                 continue
-            if arg in ['timestamp', 'order', 'committer', 'message']:
+            if arg in ['branch', 'timestamp', 'order', 'committer', 'message']:
                 abort(400, description='Not enough arguments provided to define a commit, but too many to search for a commit')
             abort(400, description=f"'{arg}' is not valid for defining commits")
 
         try:
-            commit = self.commit_context.register_commit_with_repo_and_id(
+            commit = self.commit_context.register_partial_commit(
                 repository_id=commit.get('repository_id'),
-                branch=commit.get('branch'),
-                commit_id=commit.get('id'),
+                ref=commit.get('id') or commit.get('ref'),
+                hash=commit.get('hash'),
+                revision=commit.get('revision'),
+                identifier=commit.get('identifier'),
+                fast=fast,
             )
         except (RuntimeError, ScmBase.Exception) as error:
             abort(404, description=str(error))
@@ -311,4 +328,12 @@
 
         if is_endpoint:
             return jsonify({'status': 'ok'})
-        return commit
+        return Commit(
+            repository_id=commit.repository_id,
+            id=commit.revision or commit.hash,
+            branch=commit.branch,
+            timestamp=commit.timestamp,
+            order=commit.order,
+            committer=commit.author.email if commit.author else None,
+            message=commit.message,
+        )

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -25,7 +25,6 @@
 
 from collections import defaultdict
 from flask import abort, jsonify, request
-from resultsdbpy.controller.commit import Commit
 from resultsdbpy.controller.commit_controller import uuid_range_for_query, HasCommitContext
 from resultsdbpy.controller.configuration import Configuration
 from resultsdbpy.controller.configuration_controller import configuration_for_query
@@ -84,7 +83,7 @@
                         response.append(dict(
                             configuration=Configuration.Encoder().default(config),
                             suite=suite,
-                            commits=Commit.Encoder().default(result['commits']),
+                            commits=[commit.Encoder().default(commit) for commit in result['commits']],
                             timestamp=result['timestamp'],
                             test_results=result['test_results'],
                         ))
@@ -113,7 +112,7 @@
             if not suite:
                 abort(400, description='No test suite specified')
 
-            commits = [self.commit_controller.register(commit=commit) for commit in data.get('commits', [])]
+            commits = [self.commit_controller.register(commit=commit, fast=True) for commit in data.get('commits', [])]
 
             test_results = data.get('test_results', {})
             if not test_results:
@@ -150,7 +149,7 @@
                         response.append(dict(
                             configuration=Configuration.Encoder().default(config),
                             suite=suite,
-                            commits=Commit.Encoder().default(result['commits']),
+                            commits=[commit.Encoder().default(commit) for commit in result['commits']],
                             timestamp=result['timestamp'],
                             processing=processing_results,
                         ))

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller_unittest.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller_unittest.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller_unittest.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -49,7 +49,7 @@
     def test_upload(self, client, **kwargs):
         upload_dict = dict(
             suite='layout-tests',
-            commits=[dict(repository_id='safari', id='d8bce26fa65c6fc8f39c17927abb77f69fab82fc'), dict(repository_id='webkit', id='6')],
+            commits=[dict(repository_id='safari', id='d8bce26fa65c6fc8f39c17927abb77f69fab82fc'), dict(repository_id='webkit', id=6)],
             configuration=Configuration.Encoder().default(Configuration(
                 platform='Mac', version='10.14.0', sdk='18A391',
                 is_simulator=False, architecture='x86_64',
@@ -67,7 +67,7 @@
         self.assertEqual(response.status_code, 200)
 
         retrieved = response.json()[0]
-        retrieved['commits'] = [dict(repository_id=commit['repository_id'], id=commit['id']) for commit in retrieved['commits']]
+        retrieved['commits'] = [dict(repository_id=commit['repository_id'], id=commit.get('hash', commit.get('revision'))) for commit in retrieved['commits']]
         self.assertEqual(retrieved, upload_dict)
 
     @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
@@ -180,7 +180,7 @@
             'd8bce26fa65c6fc8f39c17927abb77f69fab82fc',
             'bae5d1e90999d4f916a8a15810ccfa43f37a2fd6',
             '1abe25b443e985f93b90d830e4a7e3731336af4d',
-        ]), sorted([result['commits'][1]['id'] for result in response.json()]))
+        ]), sorted([result['commits'][1]['hash'] for result in response.json()]))
 
     @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
     @FlaskTestCase.run_with_webserver()
@@ -188,26 +188,28 @@
         response = client.get(self.URL + '/api/upload?platform=Mac&style=Release&flavor=wk2&id=d8bce26fa65c')
         self.assertEqual(response.status_code, 200)
         self.assertEqual(1, len(response.json()))
-        self.assertEqual(['d8bce26fa65c6fc8f39c17927abb77f69fab82fc'], [result['commits'][1]['id'] for result in response.json()])
+        self.assertEqual(['d8bce26fa65c6fc8f39c17927abb77f69fab82fc'], [result['commits'][1]['hash'] for result in response.json()])
 
         response = client.get(self.URL + '/api/upload?platform=Mac&style=Release&flavor=wk2&id=6')
         self.assertEqual(response.status_code, 200)
         self.assertEqual(5, len(response.json()))
-        self.assertEqual(['6'] * 5, [result['commits'][0]['id'] for result in response.json()])
+        self.assertEqual([6] * 5, [result['commits'][0]['revision'] for result in response.json()])
 
     @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
     @FlaskTestCase.run_with_webserver()
     def test_process(self, client, **kwargs):
-        response = client.post(self.URL + '/api/upload/process?platform=Mac&style=Release&flavor=wk2')
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(5, len(response.json()))
-        self.assertEqual([dict(status='ok')] * 5, [element['processing']['python-tests'] for element in response.json()])
+        with MockModelFactory.safari(), MockModelFactory.webkit():
+            response = client.post(self.URL + '/api/upload/process?platform=Mac&style=Release&flavor=wk2')
+            self.assertEqual(response.status_code, 200)
+            self.assertEqual(5, len(response.json()))
+            self.assertEqual([dict(status='ok')] * 5, [element['processing']['python-tests'] for element in response.json()])
 
     @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
     @FlaskTestCase.run_with_webserver()
     def test_process_commit(self, client, **kwargs):
-        response = client.post(self.URL + '/api/upload/process?platform=Mac&style=Release&flavor=wk2&id=d8bce26fa65c')
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(1, len(response.json()))
-        self.assertEqual(['d8bce26fa65c6fc8f39c17927abb77f69fab82fc'], [result['commits'][1]['id'] for result in response.json()])
-        self.assertEqual([dict(status='ok')], [element['processing']['python-tests'] for element in response.json()])
+        with MockModelFactory.safari(), MockModelFactory.webkit():
+            response = client.post(self.URL + '/api/upload/process?platform=Mac&style=Release&flavor=wk2&id=d8bce26fa65c')
+            self.assertEqual(response.status_code, 200)
+            self.assertEqual(1, len(response.json()))
+            self.assertEqual(['d8bce26fa65c6fc8f39c17927abb77f69fab82fc'], [result['commits'][1]['hash'] for result in response.json()])
+            self.assertEqual([dict(status='ok')], [element['processing']['python-tests'] for element in response.json()])

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -1,4 +1,4 @@
-# Copyright (C) 2019 Apple Inc. All rights reserved.
+# Copyright (C) 2019-2021 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
 from resultsdbpy.controller.commit import Commit
 from resultsdbpy.model.repository import Repository
 
-from webkitscmpy import ScmBase
+from webkitscmpy import ScmBase, Commit as ScmCommit, Contributor
 
 
 class CommitContext(object):
@@ -65,6 +65,43 @@
         uuid = columns.BigInt(primary_key=True, required=True, clustering_order='DESC')
         commit_id = columns.Text(required=True)
 
+    class CommitModelMk2(Model):
+        repository_id = columns.Text(partition_key=True, required=True)
+        people = columns.Text(required=False)
+        message = columns.Text(required=False)
+
+        identifier = columns.Text(required=False)
+        hash = columns.Text(required=False)
+        revision = columns.Integer(required=False)
+
+        def to_commit(self):
+            return ScmCommit(
+                repository_id=self.repository_id, branch=self.branch,
+                timestamp=self.uuid // Commit.TIMESTAMP_TO_UUID_MULTIPLIER,
+                order=self.uuid % Commit.TIMESTAMP_TO_UUID_MULTIPLIER,
+                author=self.people.get('author') if self.people else None,
+                message=self.message,
+                identifier=self.identifier,
+                hash=self.hash,
+                revision=self.revision,
+            )
+
+    class CommitByRef(CommitModelMk2):
+        __table_name__ = 'commits_ref_to_object'
+        ref = columns.Text(primary_key=True, required=True)
+        uuid = columns.BigInt(required=True)
+        branch = columns.Text(required=True)
+
+    class CommitByUuidAscendingMk2(CommitModelMk2):
+        __table_name__ = 'commits_uuid_to_object_ascending'
+        branch = columns.Text(partition_key=True, required=True)
+        uuid = columns.BigInt(primary_key=True, required=True, clustering_order='ASC')
+
+    class CommitByUuidDescendingMk2(CommitModelMk2):
+        __table_name__ = 'commits_uuid_to_object_descending'
+        branch = columns.Text(partition_key=True, required=True)
+        uuid = columns.BigInt(primary_key=True, required=True, clustering_order='DESC')
+
     class Branches(Model):
         __table_name__ = 'commit_branches'
         repository_id = columns.Text(partition_key=True, required=True)
@@ -80,13 +117,15 @@
         self.cassandra = cassandra
         self.repositories = {}
         self.cache_timeout = cache_timeout
+        self.name = 'commit-identifiers'
 
         with self:
-            self.cassandra.create_table(self.CommitByID)
-            self.cassandra.create_table(self.CommitByUuidAscending)
-            self.cassandra.create_table(self.CommitByUuidDescending)
-            self.cassandra.create_table(self.Branches)
+            for old in [self.CommitByID, self.CommitByUuidAscending, self.CommitByUuidDescending]:
+                self.cassandra.create_table(old)
 
+            for table in [self.CommitByRef, self.CommitByUuidAscendingMk2, self.CommitByUuidDescendingMk2, self.Branches]:
+                self.cassandra.create_table(table)
+
     def __enter__(self):
         self.cassandra.__enter__()
 
@@ -169,6 +208,22 @@
             callback,
         )
 
+    def find_commits_by_ref(self, repository_id, ref, limit=100):
+        # FIXME: Should use the redis cache, but the redis cache doesn't support new-style commits yet
+        with self:
+            if isinstance(ref, int) or ref.isdigit():
+                return [model.to_commit() for model in self.cassandra.select_from_table(
+                    self.CommitByRef.__table_name__, limit=limit,
+                    repository_id=repository_id, ref='r{}'.format(ref),
+                )]
+
+            # FIXME: SASI indecies are the canoical way to solve this problem, but require Cassandra 3.4 which
+            # hasn't been deployed to our datacenters yet. This works for commits, but is less transparent.
+            return [model.to_commit() for model in self.cassandra.select_from_table(
+                self.CommitByRef.__table_name__, limit=limit,
+                repository_id=repository_id, ref__gte=ref.lower(), ref__lte=(ref.lower() + 'g'),
+            )]
+
     def find_commits_by_uuid(self, repository_id, branch, uuid, limit=100):
         if branch is None:
             branch = self.repositories[repository_id].default_branch
@@ -298,21 +353,77 @@
                 self.Branches.__table_name__, limit=limit, repository_id=repository_id,
             )]
 
+    def register(self, configuration, commits, suite, test_results, timestamp=None):
+        try:
+            for commit in commits:
+                self.register_partial_commit(
+                    repository_id=commit.repository_id,
+                    ref=commit.id,
+                    revision=commit.revision,
+                    hash=commit.hash,
+                    fast=False,
+                )
+        except Exception as e:
+            return dict(
+                status='error',
+                description=str(e),
+            )
+
+        return dict(status='ok')
+
     def register_commit(self, commit):
-        if not isinstance(commit, Commit):
-            raise TypeError(f'Expected type {Commit}, got {type(commit)}')
+        if not isinstance(commit, ScmCommit):
+            raise TypeError(f'Expected type {ScmCommit}, got {type(commit)}')
 
         with self:
             if commit.repository_id not in self.repositories:
                 self.repositories[commit.repository_id] = Repository(key=commit.repository_id)
 
-            for table in [self.CommitByID, self.CommitByUuidAscending, self.CommitByUuidDescending]:
+            for old in [self.CommitByID, self.CommitByUuidAscending, self.CommitByUuidDescending]:
                 self.cassandra.insert_row(
+                    old.__table_name__,
+                    repository_id=commit.repository_id,
+                    branch=commit.branch,
+                    commit_id=str(commit.revision).lower() if commit.revision else commit.hash,
+                    uuid=commit.uuid,
+                    committer=commit.author.email if commit.author else None,
+                    message=commit.message,
+                )
+
+            for table in [self.CommitByUuidAscendingMk2, self.CommitByUuidDescendingMk2, self.Branches]:
+                self.cassandra.insert_row(
                     table.__table_name__,
-                    repository_id=commit.repository_id, branch=commit.branch,
-                    commit_id=str(commit.id).lower(), uuid=commit.uuid,
-                    committer=commit.committer, message=commit.message,
+                    repository_id=commit.repository_id,
+                    branch=commit.branch,
+                    revision=commit.revision,
+                    hash=commit.hash,
+                    identifier=str(commit) if commit.identifier else None,
+                    uuid=commit.uuid,
+                    committer=json.dumps(commit.author, cls=Contributor.Encoder) if commit.author else None,
+                    message=commit.message,
                 )
+
+            for key, ref_gen in (
+                ('revision', lambda commit: 'r{}'.format(commit.revision)),
+                ('hash', lambda commit: commit.hash),
+                ('identifier', str),
+            ):
+                if not getattr(commit, key):
+                    continue
+
+                self.cassandra.insert_row(
+                    self.CommitByRef.__table_name__,
+                    ref=ref_gen(commit),
+                    repository_id=commit.repository_id,
+                    branch=commit.branch,
+                    revision=commit.revision,
+                    hash=commit.hash,
+                    identifier=str(commit) if commit.identifier else None,
+                    uuid=commit.uuid,
+                    committer=json.dumps(commit.author, cls=Contributor.Encoder) if commit.author else None,
+                    message=commit.message,
+                )
+
             self.cassandra.insert_row(
                 self.Branches.__table_name__,
                 repository_id=commit.repository_id, branch=commit.branch,
@@ -319,26 +430,24 @@
             )
             return commit
 
-    def register_commit_with_repo_and_id(self, repository_id, branch, commit_id):
-        if branch is None:
-            branch = self.repositories[repository_id].default_branch
+    def register_partial_commit(self, repository_id, ref=None, revision=None, hash=None, identifier=None, fast=True):
         if repository_id not in self.repositories:
             raise RuntimeError('{} is not a recognized repository')
 
         with self:
-            commits = self.find_commits_by_id(repository_id=repository_id, branch=branch, commit_id=commit_id)
+            commits = self.find_commits_by_ref(repository_id=repository_id, ref=ref or revision or hash or identifier)
             if len(commits) > 1:
-                raise ScmBase.Exception(f'Multiple commits with the id {commit_id} exist in {repository_id} on {branch}')
-            if commits:
+                raise ScmBase.Exception(f'Multiple commits with the id {ref or revision or hash or identifier} exist in {repository_id}')
+            if commits and (fast or commits[0].identifier):
                 return commits[0]
-            commit = self.repositories[repository_id].commit_for_id(commit_id)
+            commit = self.repositories[repository_id].commit(ref=ref, revision=revision, hash=hash, identifier=identifier, fast=fast)
             return self.register_commit(commit)
 
     def url(self, commit):
-        if not isinstance(commit, Commit):
+        if not isinstance(commit, Commit) and not isinstance(commit, ScmCommit):
             raise TypeError(f'Expected type {Commit}, got {type(commit)}')
 
         repo = self.repositories.get(commit.repository_id)
         if repo:
-            return repo.url_for_commit(commit.id)
+            return repo.url_for_commit(commit.id if isinstance(commit, Commit) else commit.hash or commit.revision)
         return None

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context_unittest.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context_unittest.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/commit_context_unittest.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -53,8 +53,8 @@
                 for key, repository in dict(safari=safari, webkit=webkit).items():
                     for branch, commits in repository.commits.items():
                         for commit in commits:
-                            self.database.register_commit_with_repo_and_id(
-                                key, branch, commit.hash or commit.revision,
+                            self.database.register_partial_commit(
+                                key, ref=commit.hash or commit.revision,
                             )
 
     @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
@@ -183,7 +183,7 @@
     def test_commit_from_stash_repo(self, redis=StrictRedis, cassandra=CassandraContext):
         with MockModelFactory.safari(), MockModelFactory.webkit():
             self.init_database(redis=redis, cassandra=cassandra)
-            self.database.register_commit_with_repo_and_id('safari', 'main', 'd8bce26fa65c')
+            self.database.register_partial_commit('safari', hash='d8bce26fa65c')
             self.assertEqual(
                 [self.stash_repository.commit_for_id(id='d8bce26fa65c')],
                 self.database.find_commits_by_id(repository_id='safari', branch='main', commit_id='d8bce26fa65c'),
@@ -193,7 +193,7 @@
     def test_commit_from_svn_repo(self, redis=StrictRedis, cassandra=CassandraContext):
         with MockModelFactory.safari(), MockModelFactory.webkit():
             self.init_database(redis=redis, cassandra=cassandra)
-            self.database.register_commit_with_repo_and_id('webkit', 'trunk', 6)
+            self.database.register_partial_commit('webkit', revision=6)
             self.assertEqual(
                 [self.svn_repository.commit_for_id(id=6)],
                 self.database.find_commits_by_id(repository_id='webkit', branch='trunk', commit_id=6),

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/mock_model_factory.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/mock_model_factory.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/mock_model_factory.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -1,4 +1,4 @@
-# Copyright (C) 2019 Apple Inc. All rights reserved.
+# Copyright (C) 2019-2021 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -92,8 +92,8 @@
                 for key, repository in dict(safari=safari, webkit=webkit).items():
                     for branch, commits in repository.commits.items():
                         for commit in commits:
-                            model.commit_context.register_commit_with_repo_and_id(
-                                key, branch, commit.hash or commit.revision,
+                            model.commit_context.register_partial_commit(
+                                key, hash=commit.hash, revision=commit.revision,
                             )
         return model
 

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/model.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/model.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/model.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -92,7 +92,7 @@
             ttl_seconds=self.default_ttl_seconds,
         )
 
-        for context in [self.ci_context, self.failure_context, self.suite_context, self.test_context]:
+        for context in [self.ci_context, self.failure_context, self.suite_context, self.test_context, self.commit_context]:
             self.upload_context.register_upload_callback(context.name, context.register)
 
         self.archive_context = ArchiveContext(

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/repository.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/repository.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/repository.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -33,6 +33,9 @@
     def commit_for_id(self, id):
         raise NotImplementedError()
 
+    def commit(self, ref=None, revision=None, hash=None, identifier=None, fast=True):
+        raise NotImplementedError()
+
     def url_for_commit(self, commit):
         return None
 
@@ -61,6 +64,13 @@
             message=commit.message,
         )
 
+    def commit(self, ref=None, revision=None, hash=None, identifier=None, fast=True):
+        if identifier:
+            fast = False
+        if ref:
+            return self.remote.find(ref, include_identifier=not fast)
+        return self.remote.commit(revision=revision, hash=hash, identifier=identifier, include_identifier=not fast)
+
     def url_for_commit(self, commit):
         return f'{self.remote.url}/commits/{commit}'
 
@@ -89,6 +99,15 @@
             message=commit.message,
         )
 
+    def commit(self, ref=None, revision=None, hash=None, identifier=None, fast=True):
+        if identifier:
+            fast = False
+        if ref:
+            if isinstance(ref, int) or ref.isdigit():
+                ref = 'r{}'.format(ref)
+            return self.remote.find(ref, include_identifier=not fast)
+        return self.remote.commit(revision=revision, hash=hash, identifier=identifier, include_identifier=not fast)
+
     def url_for_commit(self, commit):
         return f'https://commits.webkit.org/r{commit}'
 

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/repository_unittest.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/repository_unittest.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/repository_unittest.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -1,4 +1,4 @@
-# Copyright (C) 2019 Apple Inc. All rights reserved.
+# Copyright (C) 2019-2021 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -31,15 +31,15 @@
         with MockModelFactory.webkit():
             svn_repo = WebKitRepository()
             self.assertTrue('webkit', svn_repo.key)
-            commit = svn_repo.commit_for_id(6)
+            commit = svn_repo.commit(revision=6)
             self.assertEqual(commit.uuid, 160163990000)
             self.assertEqual(commit.message, '6th commit')
             self.assertEqual(commit.branch, 'trunk')
 
-    def test_branch_svn(self):
+    def test_ref_svn(self):
         with MockModelFactory.webkit():
             svn_repo = WebKitRepository()
-            commit = svn_repo.commit_for_id(7)
+            commit = svn_repo.commit(ref=7)
             self.assertEqual(commit.uuid, 160164090000)
             self.assertEqual(commit.message, '7th commit')
             self.assertEqual(commit.branch, 'branch-a')
@@ -48,15 +48,23 @@
         with MockModelFactory.safari() as safari:
             git_repo = StashRepository('https://{}'.format(safari.remote))
             self.assertEqual('safari', git_repo.key)
-            commit = git_repo.commit_for_id('1abe25b443e9')
+            commit = git_repo.commit(hash='1abe25b443e9')
             self.assertEqual(commit.uuid, 160166300000)
             self.assertEqual(commit.branch, 'main')
 
+    def test_ref_stash(self):
+        with MockModelFactory.safari() as safari:
+            git_repo = StashRepository('https://{}'.format(safari.remote))
+            self.assertEqual('safari', git_repo.key)
+            commit = git_repo.commit(ref='1abe25b443e9')
+            self.assertEqual(commit.uuid, 160166300000)
+            self.assertEqual(commit.branch, 'main')
+
     def test_colliding_timestamps_stash(self):
         with MockModelFactory.safari() as safari:
             git_repo = StashRepository('https://{}'.format(safari.remote))
-            commit1 = git_repo.commit_for_id('bae5d1e90999')
-            commit2 = git_repo.commit_for_id('d8bce26fa65c')
+            commit1 = git_repo.commit(hash='bae5d1e90999')
+            commit2 = git_repo.commit(hash='d8bce26fa65c')
 
             self.assertEqual(commit1.timestamp, commit2.timestamp)
             self.assertNotEqual(commit1.uuid, commit2.uuid)
@@ -67,6 +75,6 @@
     def test_branch_stash(self):
         with MockModelFactory.safari() as safari:
             git_repo = StashRepository('https://{}'.format(safari.remote))
-            commit = git_repo.commit_for_id('621652add7fc')
+            commit = git_repo.commit(hash='621652add7fc')
             self.assertEqual(commit.uuid, 160166600000)
             self.assertEqual(commit.branch, 'branch-a')

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -34,7 +34,9 @@
 from resultsdbpy.model.commit_context import CommitContext
 from resultsdbpy.model.configuration_context import ClusteredByConfiguration
 
+from webkitscmpy import Commit as ScmCommit
 
+
 class UploadContext(object):
     QUEUE_NAME = 'upload_queue'
     PROCESS_TIMEOUT = 7 * 24 * 60 * 60
@@ -61,7 +63,7 @@
 
         def unpack(self):
             return dict(
-                commits=[Commit.from_json(element) for element in json.loads(UploadContext.from_zip(bytearray(self.commits)))],
+                commits=[ScmCommit.from_json(element) for element in json.loads(UploadContext.from_zip(bytearray(self.commits)))],
                 sdk=None if self.sdk == '?' else self.sdk,
                 test_results=json.loads(UploadContext.from_zip(bytearray(self.test_results))),
                 timestamp=calendar.timegm(self.time_uploaded.timetuple()),
@@ -81,7 +83,7 @@
 
         def unpack(self):
             return dict(
-                commits=[Commit.from_json(element) for element in json.loads(UploadContext.from_zip(bytearray(self.commits)))],
+                commits=[ScmCommit.from_json(element) for element in json.loads(UploadContext.from_zip(bytearray(self.commits)))],
                 sdk=None if self.sdk == '?' else self.sdk,
                 test_results=json.loads(UploadContext.from_zip(bytearray(self.test_results))),
                 timestamp=calendar.timegm(self.time_uploaded.timetuple()),
@@ -179,7 +181,7 @@
                 data = ""
                 self.synchronously_process_test_results(
                     configuration=Configuration.from_json(data['configuration']),
-                    commits=[Commit.from_json(commit_json) for commit_json in data['commits']],
+                    commits=[ScmCommit.from_json(commit_json) for commit_json in data['commits']],
                     suite=data['suite'],
                     timestamp=data['timestamp'],
                     test_results=data['test_results'],
@@ -229,7 +231,7 @@
                 json.dumps(dict(
                     configuration=Configuration.Encoder().default(configuration),
                     suite=suite,
-                    commits=Commit.Encoder().default(commits),
+                    commits=[commit.Encoder().default(commit) for commit in commits],
                     timestamp=timestamp,
                     test_results=test_results,
                 )),
@@ -241,7 +243,7 @@
         if not isinstance(suite, str):
             raise TypeError(f'Expected type {str}, got {type(suite)}')
         for commit in commits:
-            if not isinstance(commit, Commit):
+            if not isinstance(commit, ScmCommit) and not isinstance(commit, Commit):
                 raise TypeError(f'Expected type {Commit}, got {type(commit)}')
         if len(commits) < 1:
             raise ValueError('Each test result must have at least 1 associated commit')
@@ -265,7 +267,7 @@
                 self.configuration_context.insert_row_with_configuration(
                     self.UploadsByConfiguration.__table_name__, configuration=configuration,
                     suite=suite, branch=branch, uuid=uuid, sdk=configuration.sdk or '?', time_uploaded=timestamp,
-                    commits=self.to_zip(json.dumps(commits, cls=Commit.Encoder)),
+                    commits=self.to_zip(json.dumps(commits, cls=commits[0].Encoder)),
                     test_results=self.to_zip(json.dumps(test_results)),
                     upload_version=version,
                     ttl=int((uuid // Commit.TIMESTAMP_TO_UUID_MULTIPLIER) + self.ttl_seconds - time.time()) if self.ttl_seconds else None,

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context_unittest.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context_unittest.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/model/upload_context_unittest.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -135,18 +135,19 @@
         self.init_database(redis=redis, cassandra=cassandra)
         MockModelFactory.add_mock_results(self.model)
 
-        configuration_to_search = Configuration(platform='iOS', version='12.0.0', is_simulator=True, style='Asan')
-        configuration, uploads = next(iter(self.model.upload_context.find_test_results(configurations=[configuration_to_search], suite='layout-tests', recent=False).items()))
-        self.model.upload_context.process_test_results(
-            configuration=configuration,
-            commits=uploads[0]['commits'],
-            suite='layout-tests',
-            test_results=uploads[0]['test_results'],
-            timestamp=uploads[0]['timestamp'],
-        )
+        with MockModelFactory.safari(), MockModelFactory.webkit():
+            configuration_to_search = Configuration(platform='iOS', version='12.0.0', is_simulator=True, style='Asan')
+            configuration, uploads = next(iter(self.model.upload_context.find_test_results(configurations=[configuration_to_search], suite='layout-tests', recent=False).items()))
+            self.model.upload_context.process_test_results(
+                configuration=configuration,
+                commits=uploads[0]['commits'],
+                suite='layout-tests',
+                test_results=uploads[0]['test_results'],
+                timestamp=uploads[0]['timestamp'],
+            )
 
-        # Using suite results as a proxy to tell if callbacks were triggered
-        self.assertEqual(1, len(self.model.suite_context.find_by_commit(configurations=[Configuration()], suite='layout-tests')))
+            # Using suite results as a proxy to tell if callbacks were triggered
+            self.assertEqual(1, len(self.model.suite_context.find_by_commit(configurations=[Configuration()], suite='layout-tests')))
 
     @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
     def test_async_callback(self, redis=StrictRedis, cassandra=CassandraContext):
@@ -153,17 +154,19 @@
         self.init_database(redis=redis, cassandra=cassandra, async_processing=True)
         MockModelFactory.add_mock_results(self.model)
 
-        configuration_to_search = Configuration(platform='iOS', version='12.0.0', is_simulator=True, style='Asan')
-        configuration, uploads = next(iter(self.model.upload_context.find_test_results(configurations=[configuration_to_search], suite='layout-tests', recent=False).items()))
-        self.model.upload_context.process_test_results(
-            configuration=configuration,
-            commits=uploads[0]['commits'],
-            suite='layout-tests',
-            test_results=uploads[0]['test_results'],
-            timestamp=uploads[0]['timestamp'],
-        )
+        with MockModelFactory.safari(), MockModelFactory.webkit():
+            configuration_to_search = Configuration(platform='iOS', version='12.0.0', is_simulator=True, style='Asan')
+            configuration, uploads = next(iter(self.model.upload_context.find_test_results(configurations=[configuration_to_search], suite='layout-tests', recent=False).items()))
 
-        # Using suite results as a proxy to tell if callbacks were triggered
-        self.assertEqual(0, len(self.model.suite_context.find_by_commit(configurations=[Configuration()], suite='layout-tests')))
-        self.assertTrue(self.model.upload_context.do_processing_work())
-        self.assertEqual(1, len(self.model.suite_context.find_by_commit(configurations=[Configuration()], suite='layout-tests')))
+            self.model.upload_context.process_test_results(
+                configuration=configuration,
+                commits=uploads[0]['commits'],
+                suite='layout-tests',
+                test_results=uploads[0]['test_results'],
+                timestamp=uploads[0]['timestamp'],
+            )
+
+            # Using suite results as a proxy to tell if callbacks were triggered
+            self.assertEqual(0, len(self.model.suite_context.find_by_commit(configurations=[Configuration()], suite='layout-tests')))
+            self.assertTrue(self.model.upload_context.do_processing_work())
+            self.assertEqual(1, len(self.model.suite_context.find_by_commit(configurations=[Configuration()], suite='layout-tests')))

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/setup.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/resultsdbpy/setup.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/setup.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -30,7 +30,7 @@
 
 setup(
     name='resultsdbpy',
-    version='2.0.2',
+    version='2.0.3',
     description='Library for visualizing, processing and storing test results.',
     long_description=readme(),
     classifiers=[

Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/commit.py (274541 => 274542)


--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/commit.py	2021-03-17 00:52:10 UTC (rev 274541)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/commit.py	2021-03-17 00:53:41 UTC (rev 274542)
@@ -220,7 +220,7 @@
         if author and isinstance(author, dict) and author.get('name'):
             self.author = Contributor(author.get('name'), author.get('emails'))
         elif author and isinstance(author, six.string_types) and '@' in author:
-            self.author = Contributor(author, author)
+            self.author = Contributor(author, [author])
         elif author and not isinstance(author, Contributor):
             raise TypeError("Expected 'author' to be of type {}, got '{}'".format(Contributor, author))
         else:
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to