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}
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])
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])
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, } }
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, } }
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, } }
def phab_exception1(): raise PhabricatorAPIException('OOPS!')
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 ], }
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}, }
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, }, }
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, }, }