mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 01:39:21 +03:00
a487dacc4b
Summary: Previous code format attempt (D8173629) didn't cover all files due to `**/*.py` was not expanded recursively by bash. That makes certain changes larger than they should be (ex. D8675439). Now use zsh's `**/*.py` to format them. Also fix Python syntax so black can run on more files, and all lint issues. Reviewed By: phillco Differential Revision: D8696912 fbshipit-source-id: 95f07aa0c5eb1b63947b0f77f534957f4ab65364
179 lines
6.1 KiB
Python
179 lines
6.1 KiB
Python
# graphql.py
|
|
#
|
|
# A library function to call a phabricator graphql RPC.
|
|
# This replaces the Conduit methods
|
|
|
|
from __future__ import absolute_import
|
|
|
|
import json
|
|
import operator
|
|
|
|
from mercurial import encoding, pycompat, util
|
|
|
|
from . import arcconfig, phabricator_graphql_client, phabricator_graphql_client_urllib
|
|
|
|
|
|
urlreq = util.urlreq
|
|
|
|
|
|
class ClientError(Exception):
|
|
def __init__(self, code, msg):
|
|
Exception.__init__(self, msg)
|
|
self.code = code
|
|
|
|
|
|
class Client(object):
|
|
def __init__(self, repodir=None, ca_bundle=None, repo=None):
|
|
if not repodir:
|
|
repodir = pycompat.getcwd()
|
|
self._mock = "HG_ARC_CONDUIT_MOCK" in encoding.environ
|
|
if self._mock:
|
|
with open(encoding.environ["HG_ARC_CONDUIT_MOCK"], "r") as f:
|
|
self._mocked_responses = json.load(f)
|
|
# reverse since we want to use pop but still get items in
|
|
# original order
|
|
self._mocked_responses.reverse()
|
|
|
|
self._host = None
|
|
self._user = None
|
|
self._cert = None
|
|
self._oauth = None
|
|
self.ca_bundle = ca_bundle or True
|
|
self._applyarcconfig(arcconfig.loadforpath(repodir))
|
|
if not self._mock:
|
|
app_id = repo.ui.config("phabricator", "graphql_app_id")
|
|
app_token = repo.ui.config("phabricator", "graphql_app_token")
|
|
self._host = repo.ui.config("phabricator", "graphql_host")
|
|
self._client = phabricator_graphql_client.PhabricatorGraphQLClient(
|
|
phabricator_graphql_client_urllib.PhabricatorGraphQLClientRequests(),
|
|
self._cert,
|
|
self._oauth,
|
|
self._user,
|
|
"phabricator",
|
|
self._host,
|
|
app_id,
|
|
app_token,
|
|
)
|
|
|
|
def _applyarcconfig(self, config):
|
|
self._host = config.get("graphql_uri", self._host)
|
|
if "OVERRIDE_GRAPHQL_URI" in encoding.environ:
|
|
self._host = encoding.environ["OVERRIDE_GRAPHQL_URI"]
|
|
try:
|
|
hostconfig = config["hosts"][self._host]
|
|
self._user = hostconfig["user"]
|
|
self._cert = hostconfig.get("cert", None)
|
|
self._oauth = hostconfig.get("oauth", None)
|
|
except KeyError:
|
|
try:
|
|
hostconfig = config["hosts"][config["hosts"].keys()[0]]
|
|
self._user = hostconfig["user"]
|
|
self._cert = hostconfig.get("cert", None)
|
|
self._oauth = hostconfig.get("oauth", None)
|
|
except KeyError:
|
|
pass
|
|
|
|
if self._cert is None and self._oauth is None:
|
|
raise arcconfig.ArcConfigError(
|
|
"arcrc is missing user "
|
|
"credentials for host %s. use "
|
|
'"arc install-certificate" to fix.' % self._host
|
|
)
|
|
|
|
def _normalizerevisionnumbers(self, *revision_numbers):
|
|
rev_numbers = []
|
|
if isinstance(revision_numbers, str):
|
|
return [int(revision_numbers)]
|
|
for r in revision_numbers:
|
|
if isinstance(r, list) or isinstance(r, tuple):
|
|
for rr in r:
|
|
rev_numbers.extend(rr)
|
|
else:
|
|
rev_numbers.append(int(r))
|
|
return [int(x) for x in rev_numbers]
|
|
|
|
def getrevisioninfo(self, timeout, *revision_numbers):
|
|
rev_numbers = self._normalizerevisionnumbers(revision_numbers)
|
|
if self._mock:
|
|
ret = self._mocked_responses.pop()
|
|
else:
|
|
params = {"params": {"numbers": rev_numbers}}
|
|
ret = self._client.query(timeout, self._getquery(), params)
|
|
return self._processrevisioninfo(ret)
|
|
|
|
def _getquery(self):
|
|
return """
|
|
query RevisionQuery(
|
|
$params: [DifferentialRevisionQueryParams!]!
|
|
) {
|
|
query: differential_revision_query(query_params: $params) {
|
|
results {
|
|
nodes {
|
|
number
|
|
diff_status_name
|
|
latest_active_diff {
|
|
local_commit_info: diff_properties (
|
|
property_names: ["local:commits"]
|
|
) {
|
|
nodes {
|
|
property_value
|
|
}
|
|
}
|
|
}
|
|
created_time
|
|
updated_time
|
|
is_landing
|
|
differential_diffs {
|
|
count
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|
|
def _processrevisioninfo(self, ret):
|
|
try:
|
|
errormsg = ret["errors"][0]["message"]
|
|
raise ClientError(None, errormsg)
|
|
except (KeyError, TypeError):
|
|
pass
|
|
|
|
infos = {}
|
|
try:
|
|
nodes = ret["data"]["query"][0]["results"]["nodes"]
|
|
for node in nodes:
|
|
info = {}
|
|
infos[str(node["number"])] = info
|
|
|
|
status = node["diff_status_name"]
|
|
# GraphQL uses "Closed" but Conduit used "Committed" so let's
|
|
# not change the naming
|
|
if status == "Closed":
|
|
status = "Committed"
|
|
info["status"] = status
|
|
info["created"] = node["created_time"]
|
|
info["updated"] = node["updated_time"]
|
|
info["is_landing"] = node["is_landing"]
|
|
|
|
if "latest_active_diff" not in node:
|
|
continue
|
|
active_diff = node["latest_active_diff"]
|
|
|
|
info["count"] = node["differential_diffs"]["count"]
|
|
|
|
localcommitnode = active_diff["local_commit_info"]["nodes"]
|
|
if localcommitnode is not None and len(localcommitnode) == 1:
|
|
localcommits = json.loads(localcommitnode[0]["property_value"])
|
|
localcommits = sorted(
|
|
localcommits.values(),
|
|
key=operator.itemgetter("time"),
|
|
reverse=True,
|
|
)
|
|
info["hash"] = localcommits[0].get("commit", None)
|
|
|
|
except (TypeError, KeyError):
|
|
raise ClientError(None, "Unexpected graphql response format")
|
|
|
|
return infos
|