Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F7123063
D8993.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Subscribers
None
D8993.diff
View Options
diff --git a/swh/graphql/resolvers/snapshot_branch.py b/swh/graphql/resolvers/snapshot_branch.py
--- a/swh/graphql/resolvers/snapshot_branch.py
+++ b/swh/graphql/resolvers/snapshot_branch.py
@@ -3,11 +3,12 @@
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
-from collections import namedtuple
+from typing import Optional, Tuple
-from swh.graphql.errors import ObjectNotFoundError
+from swh.graphql.errors import DataError
from swh.graphql.utils import utils
-from swh.storage.interface import PagedResult
+from swh.model.model import SnapshotBranch
+from swh.storage.interface import PagedResult, PartialBranches
from .base_connection import BaseConnection
from .base_node import BaseNode
@@ -18,17 +19,21 @@
# target field for this node is a UNION type
# It is resolved in the top level (resolvers.resolvers.py)
- def _get_node_from_data(self, node_data: tuple):
- # node_data is a tuple as returned by _get_paged_result in
- # SnapshotBranchConnection and _get_node_data in AliasSnapshotBranchNode
- # overriding to support this special data structure
- branch_name, branch_obj = node_data
- node = {
- "name": branch_name,
- "type": branch_obj.target_type.value,
- "target_hash": branch_obj.target,
- }
- return namedtuple("NodeObj", node.keys())(*node.values())
+ def _get_node_from_data(
+ self, node_data: Optional[Tuple[bytes, Optional[SnapshotBranch]]]
+ ):
+ # node_data is received as a tuple from the archive
+ # (unlike an object or a dict in other cases)
+ # override this method to make a dict from this special data structure
+ structured_node_data = None
+ if node_data is not None:
+ branch_name, branch_obj = node_data
+ structured_node_data = {
+ "name": branch_name,
+ "type": branch_obj.target_type.value if branch_obj else None,
+ "target_hash": branch_obj.target if branch_obj else None,
+ }
+ return super()._get_node_from_data(structured_node_data)
def is_type_of(self):
return "Branch"
@@ -56,26 +61,28 @@
return parent.swhid
parent = parent.obj
# Reached the root query node. This will never happen with the current entrypoints
- raise ObjectNotFoundError("There is no snapshot associated with the branch")
+ # raise a DataError in this case
+ raise DataError(
+ f"Missing snapshot for the branch {self.target_hash}, last known parent is {parent}"
+ )
class AliasSnapshotBranchNode(BaseSnapshotBranchNode):
+ _can_be_null = True
obj: BaseSnapshotBranchNode
def _get_node_data(self):
+ target_branch: Optional[bytes] = self.obj.target_hash
snapshot_swhid = self.snapshot_swhid()
- target_branch = self.obj.target_hash
-
- alias_branch = self.archive.get_snapshot_branches(
+ alias_branches: Optional[PartialBranches] = self.archive.get_snapshot_branches(
snapshot_swhid.object_id, first=1, name_include=target_branch
)
- if target_branch not in alias_branch["branches"]:
- raise ObjectNotFoundError(
- f"Branch name with {target_branch.decode()} is not available"
- )
- # this will be serialized in _get_node_from_data method in the base class
- return (target_branch, alias_branch["branches"][target_branch])
+ if alias_branches and target_branch in alias_branches["branches"]:
+ # this will be converted to a dict in _get_node_from_data method in the base class
+ return (target_branch, alias_branches["branches"][target_branch])
+ # FIXME, alias branch is missing, log this event
+ return None
class SnapshotBranchConnection(BaseConnection):
@@ -106,7 +113,8 @@
# FIX in swh-storage to return PagedResult
# STORAGE-TODO
- # this will be serialized in _get_node_from_data method in the node class
+ # each result item will be converted to a dict in _get_node_from_data method
+ # in the node class
return PagedResult(
results=result["branches"].items(), next_page_token=end_cusrsor
)
diff --git a/swh/graphql/tests/data.py b/swh/graphql/tests/data.py
--- a/swh/graphql/tests/data.py
+++ b/swh/graphql/tests/data.py
@@ -13,6 +13,9 @@
Release,
Revision,
RevisionType,
+ Snapshot,
+ SnapshotBranch,
+ TargetType,
)
from swh.model.tests import swh_model_data
@@ -172,7 +175,20 @@
]
+def get_snapshots_with_missing_alias():
+ return [
+ Snapshot(
+ branches={
+ b"target/missing-alias": SnapshotBranch(
+ target_type=TargetType.ALIAS, target=b"target/revision"
+ ),
+ },
+ ),
+ ]
+
+
GRAPHQL_EXTRA_TEST_OBJECTS = {
+ "snapshot": get_snapshots_with_missing_alias(),
"release": get_releases_with_target(),
"revision": get_revisions_with_parents() + get_revisions_with_none_date(),
"directory": get_directories_with_nested_path()
diff --git a/swh/graphql/tests/functional/test_branch_connection.py b/swh/graphql/tests/functional/test_branch_connection.py
--- a/swh/graphql/tests/functional/test_branch_connection.py
+++ b/swh/graphql/tests/functional/test_branch_connection.py
@@ -6,6 +6,7 @@
import pytest
from . import utils
+from ..data import get_snapshots_with_missing_alias
def get_branches(client, **kwargs) -> tuple:
@@ -81,6 +82,20 @@
}
+@pytest.mark.parametrize("snapshot", get_snapshots_with_missing_alias())
+def test_get_branches_with_missing_alias(client, snapshot):
+ data, errors = get_branches(
+ client, swhid=str(snapshot.swhid()), first=1, types=["alias"]
+ )
+ node = data["snapshot"]["branches"]["nodes"][0]
+ assert errors is None
+ assert node == {
+ "name": {"text": "target/missing-alias"},
+ "target": None,
+ "targetType": "alias",
+ }
+
+
@pytest.mark.parametrize(
"filter_type, count, target_type, swhid_pattern",
[
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Dec 17, 6:49 PM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3213801
Attached To
D8993: [WIP] Retrun null for a missing alias branch
Event Timeline
Log In to Comment