Exemple #1
0
    def phid_query(self, *, phids=None):
        if phids is None:
            error_info = "Argument 1 passed to PhabricatorHandleQuery::withPHIDs() must be of the type array, null given, called in /app/phabricator/src/applications/phid/conduit/PHIDQueryConduitAPIMethod.php on line 28 and defined"  # noqa
            raise PhabricatorAPIException(
                error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
            )

        return {i["phid"]: deepcopy(i) for i in self._phids if i["phid"] in phids}
Exemple #2
0
    def differential_getrawdiff(self, *, diffID=None):
        def to_response(i):
            return i['rawdiff']

        diffs = [d for d in self._diffs if d['id'] == diffID]
        if diffID is None or not diffs:
            raise PhabricatorAPIException('Diff not found.',
                                          error_code='ERR_NOT_FOUND',
                                          error_info='Diff not found.')

        return to_response(diffs[0])
Exemple #3
0
    def differential_getrawdiff(self, *, diffID=None):
        def to_response(i):
            return i["rawdiff"]

        diffs = [d for d in self._diffs if d["id"] == diffID]
        if diffID is None or not diffs:
            raise PhabricatorAPIException(
                "Diff not found.",
                error_code="ERR_NOT_FOUND",
                error_info="Diff not found.",
            )

        return to_response(diffs[0])
Exemple #4
0
    def user_search(self,
                    *,
                    queryKey=None,
                    constraints={},
                    attachments={},
                    order=None,
                    before=None,
                    after=None,
                    limit=100):
        def to_response(u):
            return deepcopy({
                "id": u['id'],
                "type": u['type'],
                "phid": u['phid'],
                "fields": {
                    "username": u['userName'],
                    "realName": u['realName'],
                    "roles": u['roles'],
                    "dateCreated": u['dateCreated'],
                    "dateModified": u['dateModified'],
                    "policy": u['policy'],
                },
                "attachments": {},
            })

        items = [u for u in self._users]

        if 'ids' in constraints:
            if not constraints['ids']:
                error_info = 'Error while reading "ids": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(error_info,
                                              error_code='ERR-CONDUIT-CORE',
                                              error_info=error_info)

            items = [i for i in items if i['id'] in constraints['ids']]

        if 'phids' in constraints:
            if not constraints['phids']:
                error_info = 'Error while reading "phids": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(error_info,
                                              error_code='ERR-CONDUIT-CORE',
                                              error_info=error_info)

            items = [i for i in items if i['phid'] in constraints['phids']]

        if 'usernames' in constraints:
            if not constraints['usernames']:
                error_info = 'Error while reading "usernames": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(error_info,
                                              error_code='ERR-CONDUIT-CORE',
                                              error_info=error_info)

            items = [
                i for i in items if i['userName'] in constraints['usernames']
            ]

        if 'nameLike' in constraints:
            items = [
                i for i in items if constraints['nameLike'] in i['userName']
            ]

        return {
            "data": [to_response(i) for i in items],
            "maps": {},
            "query": {
                "queryKey": queryKey,
            },
            "cursor": {
                "limit": limit,
                "after": after,
                "before": before,
                "order": order,
            }
        }
Exemple #5
0
    def edge_search(self,
                    *,
                    sourcePHIDs=None,
                    types=None,
                    destinationPHIDs=None,
                    before=None,
                    after=None,
                    limit=100):
        def to_response(i):
            return deepcopy({
                'edgeType': i['edgeType'],
                'sourcePHID': i['sourcePHID'],
                'destinationPHID': i['destinationPHID'],
            })

        if not sourcePHIDs:
            error_info = 'Edge object query must be executed with a nonempty list of source PHIDs.'  # noqa
            raise PhabricatorAPIException(error_info,
                                          error_code='ERR-CONDUIT-CORE',
                                          error_info=error_info)

        if not types:
            error_info = 'Edge search must specify a nonempty list of edge types.'  # noqa
            raise PhabricatorAPIException(error_info,
                                          error_code='ERR-CONDUIT-CORE',
                                          error_info=error_info)

        if not set(types) <= set((
                'commit.revision',
                'commit.task',
                'mention',
                'mentioned-in',
                'revision.child',
                'revision.commit',
                'revision.parent',
                'revision.task',
                'task.commit',
                'task.duplicate',
                'task.merged-in',
                'task.parent',
                'task.revision',
                'task.subtask',
        )):
            error_info = 'Edge type "<type-is-here>" is not a recognized edge type.'  # noqa
            raise PhabricatorAPIException(error_info,
                                          error_code='ERR-CONDUIT-CORE',
                                          error_info=error_info)

        items = [e for e in self._edges]
        items = [i for i in items if i['sourcePHID'] in sourcePHIDs]
        items = [i for i in items if i['edgeType'] in types]

        if destinationPHIDs:
            items = [
                i for i in items if i['destinationPHID'] in destinationPHIDs
            ]

        return {
            "data": [to_response(i) for i in items],
            "cursor": {
                "limit": limit,
                "after": after,
                "before": before,
            }
        }
Exemple #6
0
    def project_search(self,
                       *,
                       queryKey=None,
                       constraints={},
                       attachments={},
                       order=None,
                       before=None,
                       after=None,
                       limit=100):
        def to_response(i):
            return deepcopy({
                "id": i['id'],
                "type": i['type'],
                "phid": i['phid'],
                "fields": {
                    "name": i['name'],
                    "slug": i['slug'],
                    "milestone": i['milestone'],
                    "depth": i['depth'],
                    "parent": i['parent'],
                    "icon": {
                        "key": i['icon']['key'],
                        "name": i['icon']['name'],
                        "icon": i['icon']['icon'],
                    },
                    "color": {
                        "key": i['color']['key'],
                        "name": i['color']['name'],
                    },
                    "dateCreated": i['dateCreated'],
                    "dateModified": i['dateModified'],
                    "policy": {
                        "view": i['policy']['view'],
                        "edit": i['policy']['edit'],
                        "join": i['policy']['join'],
                    },
                    "description": i['description'],
                },
                "attachments": {},
            })

        items = [p for p in self._projects]

        if 'ids' in constraints:
            if not constraints['ids']:
                error_info = 'Error while reading "ids": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(error_info,
                                              error_code='ERR-CONDUIT-CORE',
                                              error_info=error_info)

            items = [i for i in items if i['id'] in constraints['ids']]

        if 'phids' in constraints:
            if not constraints['phids']:
                error_info = 'Error while reading "phids": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(error_info,
                                              error_code='ERR-CONDUIT-CORE',
                                              error_info=error_info)

            items = [i for i in items if i['phid'] in constraints['phids']]

        return {
            "data": [to_response(i) for i in items],
            "maps": {
                "slugMap": {},
            },
            "query": {
                "queryKey": queryKey,
            },
            "cursor": {
                "limit": limit,
                "after": after,
                "before": before,
                "order": order,
            }
        }
Exemple #7
0
 def phab_exception1():
     raise PhabricatorAPIException('OOPS!')
Exemple #8
0
    def differential_revision_edit(self, *, transactions=None, objectIdentifier=None):
        # WARNING: This mock does not apply the real result of these
        # transactions, it only validates that the phabricator method
        # was called (mostly) correctly and performs a NOOP. Any testing
        # requiring something more advanced should isolate the component
        # and take care of mocking things manually.
        TRANSACTION_TYPES = [
            "update",
            "title",
            "summary",
            "testPlan",
            "reviewers.add",
            "reviewers.remove",
            "reviewers.set",
            "repositoryPHID",
            "tasks.add",
            "tasks.remove",
            "tasks.set",
            "parents.add",
            "parents.remove",
            "parents.set",
            "children.add",
            "children.remove",
            "children.set",
            "plan-changes",
            "request-review",
            "close",
            "reopen",
            "abandon",
            "accept",
            "reclaim",
            "reject",
            "commandeer",
            "resign",
            "draft",
            "view",
            "edit",
            "projects.add",
            "projects.remove",
            "projects.set," "subscribers.add",
            "subscribers.remove",
            "subscribers.set",
            "phabricator:auditors",
            "bugzilla.bug-id",
            "comment",
        ]

        if transactions is None or (
            not isinstance(transactions, list) and not isinstance(transactions, dict)
        ):
            error_info = 'Parameter "transactions" is not a list of transactions.'
            raise PhabricatorAPIException(
                error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
            )

        # Normalize transactions into a unified format (they can either be a
        # list or a dict). Internally phabricator treats lists as ordered
        # dictionaries (php arrays) where the keys are integers.
        if isinstance(transactions, list):
            transactions = list(enumerate(transactions))
        elif isinstance(transactions, dict):
            transactions = list((k, v) for k, v, in transactions.items())

        # Validate each transaction.
        for key, t in transactions:
            if not isinstance(t, dict):
                error_info = f'Parameter "transactions" must contain a list of transaction descriptions, but item with key "{key}" is not a dictionary.'  # noqa
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )

            if "type" not in t:
                error_info = f'Parameter "transactions" must contain a list of transaction descriptions, but item with key "{key}" is missing a "type" field. Each transaction must have a type field.'  # noqa
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )

            if t["type"] not in TRANSACTION_TYPES:
                given_type = t["type"]
                valid_types = " ,".join(TRANSACTION_TYPES)
                error_info = f'Transaction with key "{key}" has invalid type "{given_type}". This type is not recognized. Valid types are: {valid_types}.'  # noqa
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )

        if objectIdentifier is None:
            # A revision is being created, it must have the "title" and "update"
            # transactions present.
            transaction_types = [t[1]["type"] for t in transactions]
            if "title" not in transaction_types or "update" not in transaction_types:
                error_info = "Validation errors:"
                if "title" not in transaction_types:
                    error_info = error_info + "\n  - Revisions must have a title."
                if "update" not in transaction_types:
                    error_info = (
                        error_info
                        + "\n  - "
                        + "You must specify an initial diff when creating a revision."
                    )
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )

        def identifier_to_revision(i):
            for r in self._revisions:
                if r["phid"] == i or r["id"] == i or "D{}".format(r["id"]) == i:
                    return r
            return None

        revision = identifier_to_revision(objectIdentifier)
        if objectIdentifier is not None and revision is None:
            error_info = (
                f'Monogram "{objectIdentifier}" does not identify a valid object.'
            )
            raise PhabricatorAPIException(
                error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
            )

        # WARNING: This assumes all transactions actually applied. If a
        # transaction is a NOOP (such as a projects.remove which attempts
        # to remove a project that isn't there) it will not be listed
        # in the returned transactions list. Do not trust this mock for
        # testing details about the returned data.
        return {
            "object": {"id": revision["id"], "phid": revision["phid"]},
            "transactions": [
                {"phid": "PHID-XACT-DREV-fakeplaceholder"} for t in transactions
            ],
        }
Exemple #9
0
    def edge_search(
        self,
        *,
        sourcePHIDs=None,
        types=None,
        destinationPHIDs=None,
        before=None,
        after=None,
        limit=100,
    ):
        def to_response(i):
            return deepcopy(
                {
                    "edgeType": i["edgeType"],
                    "sourcePHID": i["sourcePHID"],
                    "destinationPHID": i["destinationPHID"],
                }
            )

        if not sourcePHIDs:
            error_info = "Edge object query must be executed with a nonempty list of source PHIDs."  # noqa
            raise PhabricatorAPIException(
                error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
            )

        if not types:
            error_info = "Edge search must specify a nonempty list of edge types."
            raise PhabricatorAPIException(
                error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
            )

        if not set(types) <= set(
            (
                "commit.revision",
                "commit.task",
                "mention",
                "mentioned-in",
                "revision.child",
                "revision.commit",
                "revision.parent",
                "revision.task",
                "task.commit",
                "task.duplicate",
                "task.merged-in",
                "task.parent",
                "task.revision",
                "task.subtask",
            )
        ):
            error_info = 'Edge type "<type-is-here>" is not a recognized edge type.'
            raise PhabricatorAPIException(
                error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
            )

        items = [e for e in self._edges]
        items = [i for i in items if i["sourcePHID"] in sourcePHIDs]
        items = [i for i in items if i["edgeType"] in types]

        if destinationPHIDs:
            items = [i for i in items if i["destinationPHID"] in destinationPHIDs]

        return {
            "data": [to_response(i) for i in items],
            "cursor": {"limit": limit, "after": after, "before": before},
        }
Exemple #10
0
    def project_search(
        self,
        *,
        queryKey=None,
        constraints={},
        attachments={},
        order=None,
        before=None,
        after=None,
        limit=100,
    ):
        def to_response(i):
            return deepcopy(
                {
                    "id": i["id"],
                    "type": i["type"],
                    "phid": i["phid"],
                    "fields": {
                        "name": i["name"],
                        "slug": i["slug"],
                        "milestone": i["milestone"],
                        "depth": i["depth"],
                        "parent": i["parent"],
                        "icon": {
                            "key": i["icon"]["key"],
                            "name": i["icon"]["name"],
                            "icon": i["icon"]["icon"],
                        },
                        "color": {"key": i["color"]["key"], "name": i["color"]["name"]},
                        "dateCreated": i["dateCreated"],
                        "dateModified": i["dateModified"],
                        "policy": {
                            "view": i["policy"]["view"],
                            "edit": i["policy"]["edit"],
                            "join": i["policy"]["join"],
                        },
                        "description": i["description"],
                    },
                    "attachments": {},
                }
            )

        items = [p for p in self._projects]

        if "ids" in constraints:
            if not constraints["ids"]:
                error_info = 'Error while reading "ids": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )

            items = [i for i in items if i["id"] in constraints["ids"]]

        if "phids" in constraints:
            if not constraints["phids"]:
                error_info = 'Error while reading "phids": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )

            items = [i for i in items if i["phid"] in constraints["phids"]]

        if "slugs" in constraints:
            if not constraints["slugs"]:
                error_info = 'Error while reading "slugs": Expected a nonempty list, but value is an empty list.'  # noqa
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )

            items = [i for i in items if i["slug"] in constraints["slugs"]]

        return {
            "data": [to_response(i) for i in items],
            "maps": {"slugMap": {}},
            "query": {"queryKey": queryKey},
            "cursor": {
                "limit": limit,
                "after": after,
                "before": before,
                "order": order,
            },
        }
Exemple #11
0
    def transaction_search(
        self,
        *,
        objectIdentifier=None,
        constraints={},
        order=None,
        before=None,
        after=None,
        limit=100,
    ):
        def to_response(i):
            # Explicitly tell the developer using the mock that they need to check the
            # type of transaction they are using and make sure it is serialized
            # correctly by this function.
            if i["type"] not in ("comment", "dummy"):
                raise ValueError(
                    "PhabricatorDouble transactions do not have support"
                    'for the "{}" transaction type. '
                    "If you have added use of a new transaction type please "
                    "update PhabricatorDouble to support it.".format(i["type"])
                )
            return deepcopy(
                {
                    "id": i["id"],
                    "phid": i["phid"],
                    "type": i["type"],
                    "authorPHID": i["authorPHID"],
                    "objectPHID": i["objectPHID"],
                    "dateCreated": i["dateCreated"],
                    "dateModified": i["dateModified"],
                    "groupID": i["groupID"],
                    "comments": i["comments"],
                    "fields": i["fields"],
                }
            )

        items = list(self._transactions)

        if objectIdentifier:
            items = [i for i in items if i["objectPHID"] == objectIdentifier]
        else:
            error_info = 'When calling "transaction.search", you must provide an object to retrieve transactions for.'  # noqa
            raise PhabricatorAPIException(
                error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
            )

        if constraints and "phids" in constraints:
            phids = constraints["phids"]
            if not phids:
                error_info = 'Constraint "phids" to "transaction.search" requires nonempty list, empty list provided.'  # noqa
                raise PhabricatorAPIException(
                    error_info, error_code="ERR-CONDUIT-CORE", error_info=error_info
                )
            items = [i for i in items if i["phid"] in phids]

        if constraints and "authorPHIDs" in constraints:
            items = [i for i in items if i["authorPHIDs"] in constraints["authorPHIDs"]]

        if after is None:
            after = 0

        next_page_end = after + limit
        page = items[after:next_page_end]
        # Set the 'after' cursor.
        if len(page) < limit:
            # This is the last page of results.
            after = None
        else:
            # Set the cursor to the next page of results.
            after = next_page_end

        return {
            "data": [to_response(i) for i in page],
            "cursor": {
                "limit": limit,
                "after": after,
                "before": before,
                "order": order,
            },
        }