Page MenuHomeSoftware Heritage

D8993.diff
No OneTemporary

D8993.diff

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

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

Event Timeline