From c69d219fdcfd3df73c269c3620715affba191a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vilhelm=20K=2E=20Vard=C3=B8y?= Date: Wed, 26 Feb 2014 00:37:26 +0000 Subject: [PATCH 01/44] Rename session property from conduit to _conduit to avoid conflict. There's a few some-time useful calls (especially the ping method) in the conduit namespace which naming the property conduit disallows usage of. --- phabricator/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 40fb669..22770d6 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -231,7 +231,7 @@ def validate_kwarg(key, target): raise ValueError('Wrong arguemnt type: %s is not a list of %ss' % (k, resource['required'][k][0])) raise ValueError('Wrong arguemnt type: %s is not a %s' % (k, resource['required'][k])) - conduit = self.api.conduit + conduit = self.api._conduit if conduit: # Already authenticated, add session key to json data @@ -244,7 +244,7 @@ def validate_kwarg(key, target): else: # Authorization is required, silently auth the user self.api.connect() - kwargs['__conduit__'] = self.api.conduit + kwargs['__conduit__'] = self.api._conduit url = urlparse.urlparse(self.api.host) if url.scheme == 'https': @@ -305,7 +305,7 @@ def __init__(self, username=None, certificate=None, host=None, self.client = 'python-phabricator' self.clientVersion = 1 self.clientDescription = socket.gethostname() + ':python-phabricator' - self.conduit = None + self._conduit = None super(Phabricator, self).__init__(self) @@ -318,7 +318,7 @@ def connect(self): response = auth(user=self.username, host=self.host, client=self.client, clientVersion=self.clientVersion) - self.conduit = { + self._conduit = { 'sessionKey': response.sessionKey, 'connectionID': response.connectionID } From 392e7ae3a7cc30519939ee83dbf3c5774b93131b Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 6 Jul 2015 14:36:06 +0100 Subject: [PATCH 02/44] Configure universal wheel building --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..3c6e79c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 From 21cf33c9a868b006f7c5ca723645b1f02a2a008e Mon Sep 17 00:00:00 2001 From: Gustavo Noronha Silva Date: Fri, 26 Jun 2015 12:03:47 -0300 Subject: [PATCH 03/44] Support new style token-based authentication Phabricator has moved on from the clunky user+certificate-based authentication scheme into one that provides the API user with a single token that can be used directly. This change adds support for that and prefers it when available. Fixes #22. --- phabricator/__init__.py | 16 +++++++++++++--- phabricator/tests.py | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 94d60c1..5214fa7 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -309,15 +309,19 @@ class Phabricator(Resource): } def __init__(self, username=None, certificate=None, host=None, - timeout=5, response_format='json', **kwargs): + timeout=5, response_format='json', token=None, **kwargs): # Set values in ~/.arcrc as defaults if ARCRC: self.host = host if host else ARCRC['hosts'].keys()[0] - self.username = username if username else ARCRC['hosts'][self.host]['user'] - self.certificate = certificate if certificate else ARCRC['hosts'][self.host]['cert'] + if token or ARCRC['hosts'][self.host].has_key('token'): + self.token = token if token else ARCRC['hosts'][self.host]['token'] + else: + self.username = username if username else ARCRC['hosts'][self.host]['user'] + self.certificate = certificate if certificate else ARCRC['hosts'][self.host]['cert'] else: self.host = host + self.token = token self.username = username self.certificate = certificate @@ -334,6 +338,12 @@ def _request(self, **kwargs): raise SyntaxError('You cannot call the Conduit API without a resource.') def connect(self): + if self.token: + self.conduit = { + 'token': self.token + } + return + auth = Resource(api=self, method='conduit', endpoint='connect') response = auth(user=self.username, host=self.host, diff --git a/phabricator/tests.py b/phabricator/tests.py index 7d0a157..70aa010 100644 --- a/phabricator/tests.py +++ b/phabricator/tests.py @@ -9,6 +9,9 @@ 'maniphest.find': '{"result":{"PHID-TASK-4cgpskv6zzys6rp5rvrc":{"id":"722","phid":"PHID-TASK-4cgpskv6zzys6rp5rvrc","authorPHID":"PHID-USER-5022a9389121884ab9db","ownerPHID":"PHID-USER-5022a9389121884ab9db","ccPHIDs":["PHID-USER-5022a9389121884ab9db","PHID-USER-ba8aeea1b3fe2853d6bb"],"status":"3","priority":"Needs Triage","title":"Relations should be two-way","description":"When adding a differential revision you can specify Maniphest Tickets to add the relation. However, this doesnt add the relation from the ticket -> the differently.(This was added via the commit message)","projectPHIDs":["PHID-PROJ-358dbc2e601f7e619232","PHID-PROJ-f58a9ac58c333f106a69"],"uri":"https:\/\/secure.phabricator.com\/T722","auxiliary":[],"objectName":"T722","dateCreated":"1325553508","dateModified":"1325618490"}},"error_code":null,"error_info":null}' } +# Protect against local user's .arcrc interference. +phabricator.ARCRC = {} + class PhabricatorTest(unittest.TestCase): def setUp(self): self.api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') From 354cedad99852c0ff66ed5af57fce38551e54832 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 20 Nov 2015 16:04:11 +0200 Subject: [PATCH 04/44] Bump to 0.5.0 --- CHANGES | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 65e025e..5431e61 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.5.0 + +* Support new style token-based authentication + 0.4.0 * Update interfaces.json to Phab @ e75b389 diff --git a/setup.py b/setup.py index b765db7..1b05c2e 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setup( name='phabricator', - version='0.4.0', + version='0.5.0', author='DISQUS', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator', From e624385d49e8a3fe0c1c9af3c40fc01b9b3ec191 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 25 Dec 2015 16:39:42 +0200 Subject: [PATCH 05/44] Add IntelliJ files to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 51593c3..f832a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.egg-info build/ dist/ +.idea From 3a0b7367bbc0681de9f80216b9321c8e58af0fe1 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 25 Dec 2015 17:27:50 +0200 Subject: [PATCH 06/44] Add Python 3 support --- phabricator/__init__.py | 92 ++++++++++++++++++----------------------- phabricator/_compat.py | 36 ++++++++++++++++ phabricator/tests.py | 83 +++++++++++++++++++++++-------------- setup.py | 23 +++++++++-- 4 files changed, 150 insertions(+), 84 deletions(-) create mode 100644 phabricator/_compat.py diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 5214fa7..b3c0f46 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -14,21 +14,23 @@ except: __version__ = 'unknown' +import collections import copy import hashlib -import httplib import json import os.path import re import socket import time -import urllib -import urlparse -from collections import defaultdict +from ._compat import ( + MutableMapping, iteritems, string_types, httplib, urlparse, urlencode, +) + __all__ = ['Phabricator'] + # Default phabricator interfaces INTERFACES = json.loads(open(os.path.join(os.path.dirname(__file__), 'interfaces.json'), 'r').read()) @@ -79,11 +81,11 @@ 'pair': tuple, # str types - 'str': basestring, - 'string': basestring, - 'phid': basestring, - 'guids': basestring, - 'type': basestring, + 'str': string_types, + 'string': string_types, + 'phid': string_types, + 'guids': string_types, + 'type': string_types, } STR_RE = re.compile(r'([a-zA-Z_]+)') @@ -108,9 +110,9 @@ def map_param_type(param_type): sub_match = STR_RE.match(sub_type) sub_type = sub_match.group(0).lower() - return [PARAM_TYPE_MAP.setdefault(sub_type, basestring)] + return [PARAM_TYPE_MAP.setdefault(sub_type, string_types)] - return PARAM_TYPE_MAP.setdefault(main_type, basestring) + return PARAM_TYPE_MAP.setdefault(main_type, string_types) def parse_interfaces(interfaces): @@ -119,9 +121,9 @@ def parse_interfaces(interfaces): This performs the logic of parsing the non-standard params dict and then returning a dict Resource can understand """ - parsed_interfaces = defaultdict(dict) + parsed_interfaces = collections.defaultdict(dict) - for m, d in interfaces.iteritems(): + for m, d in iteritems(interfaces): app, func = m.split('.', 1) method = parsed_interfaces[app][func] = {} @@ -133,7 +135,7 @@ def parse_interfaces(interfaces): method['optional'] = {} method['required'] = {} - for name, type_info in dict(d['params']).iteritems(): + for name, type_info in iteritems(dict(d['params'])): # Usually in the format: info_pieces = type_info.split(' ', 1) @@ -176,42 +178,29 @@ class InvalidAccessToken(APIError): pass -class Result(object): +class Result(MutableMapping): def __init__(self, response): self.response = response - def __repr__(self): - return '<%s: %s>' % (self.__class__.__name__, repr(self.response)) - - def __iter__(self): - for r in self.response: - yield r - def __getitem__(self, key): return self.response[key] - def __getattr__(self, key): - return self.response[key] + __getattr__ = __getitem__ + + def __setitem__(self, key, value): + self.response[key] = value - def __getstate__(self): - return self.response + def __delitem__(self, key): + del self.response[key] - def __setstate__(self, state): - self.response = state + def __iter__(self): + return iter(self.response) def __len__(self): return len(self.response.keys()) - def keys(self): - return self.response.keys() - - def iteritems(self): - for k, v in self.response.iteritems(): - yield k, v - - def itervalues(self): - for v in self.response.itervalues(): - yield v + def __repr__(self): + return '<%s: %s>' % (type(self).__name__, repr(self.response)) class Resource(object): @@ -240,17 +229,17 @@ def validate_kwarg(key, target): # Always allow list if isinstance(key, list): return all([validate_kwarg(x, target[0]) for x in key]) - return isinstance(key, target) - - for k in resource.get('required', []): - if k not in [x.split(':')[0] for x in kwargs.keys()]: - raise ValueError('Missing required argument: %s' % k) - if isinstance(kwargs.get(k), list) and not isinstance(resource['required'][k], list): - raise ValueError('Wrong argument type: %s is not a list' % k) - elif not validate_kwarg(kwargs.get(k), resource['required'][k]): - if isinstance(resource['required'][k], list): - raise ValueError('Wrong arguemnt type: %s is not a list of %ss' % (k, resource['required'][k][0])) - raise ValueError('Wrong arguemnt type: %s is not a %s' % (k, resource['required'][k])) + return isinstance(key, tuple(target) if isinstance(target, list) else target) + + for key, val in resource.get('required', {}).items(): + if key not in [x.split(':')[0] for x in kwargs.keys()]: + raise ValueError('Missing required argument: %s' % key) + if isinstance(kwargs.get(key), list) and not isinstance(val, list): + raise ValueError('Wrong argument type: %s is not a list' % key) + elif not validate_kwarg(kwargs.get(key), val): + if isinstance(val, list): + raise ValueError('Wrong argument type: %s is not a list of %ss' % (key, val[0])) + raise ValueError('Wrong argument type: %s is not a %s' % (key, val)) conduit = self.api.conduit @@ -280,7 +269,7 @@ def validate_kwarg(key, target): 'Content-Type': 'application/x-www-form-urlencoded' } - body = urllib.urlencode({ + body = urlencode({ "params": json.dumps(kwargs), "output": self.api.response_format }) @@ -355,7 +344,8 @@ def connect(self): } def generate_hash(self, token): - return hashlib.sha1(token + self.api.certificate).hexdigest() + source_string = (token + self.api.certificate).encode('utf-8') + return hashlib.sha1(source_string).hexdigest() def update_interfaces(self): query = Resource(api=self, method='conduit', endpoint='query') diff --git a/phabricator/_compat.py b/phabricator/_compat.py new file mode 100644 index 0000000..68138ea --- /dev/null +++ b/phabricator/_compat.py @@ -0,0 +1,36 @@ +import sys + +PY3 = sys.version_info[0] >= 3 + +try: + from collections.abc import MutableMapping +except ImportError: + from collections import MutableMapping + +try: + import httplib +except ImportError: + import http.client as httplib + +try: + import urlparse +except ImportError: + import urllib.parse as urlparse + +try: + from urllib import urlencode +except ImportError: + from urllib.parse import urlencode + +if PY3: + str_type = str + string_types = str, + + def iteritems(d, **kw): + return iter(d.items(**kw)) +else: + str_type = unicode + string_types = basestring, + + def iteritems(d, **kw): + return d.iteritems(**kw) diff --git a/phabricator/tests.py b/phabricator/tests.py index 70aa010..5373feb 100644 --- a/phabricator/tests.py +++ b/phabricator/tests.py @@ -1,7 +1,21 @@ +try: + import unittest2 as unittest +except ImportError: + import unittest + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +try: + import unittest.mock as mock +except ImportError: + import mock + + import phabricator -import unittest -from StringIO import StringIO -from mock import patch, Mock + RESPONSES = { 'conduit.connect': '{"result":{"connectionID":1759,"sessionKey":"lwvyv7f6hlzb2vawac6reix7ejvjty72svnir6zy","userPHID":"PHID-USER-6ij4rnamb2gsfpdkgmny"},"error_code":null,"error_info":null}', @@ -9,69 +23,78 @@ 'maniphest.find': '{"result":{"PHID-TASK-4cgpskv6zzys6rp5rvrc":{"id":"722","phid":"PHID-TASK-4cgpskv6zzys6rp5rvrc","authorPHID":"PHID-USER-5022a9389121884ab9db","ownerPHID":"PHID-USER-5022a9389121884ab9db","ccPHIDs":["PHID-USER-5022a9389121884ab9db","PHID-USER-ba8aeea1b3fe2853d6bb"],"status":"3","priority":"Needs Triage","title":"Relations should be two-way","description":"When adding a differential revision you can specify Maniphest Tickets to add the relation. However, this doesnt add the relation from the ticket -> the differently.(This was added via the commit message)","projectPHIDs":["PHID-PROJ-358dbc2e601f7e619232","PHID-PROJ-f58a9ac58c333f106a69"],"uri":"https:\/\/secure.phabricator.com\/T722","auxiliary":[],"objectName":"T722","dateCreated":"1325553508","dateModified":"1325618490"}},"error_code":null,"error_info":null}' } +CERTIFICATE = ( + 'fdhcq3zsyijnm4h6gmh43zue5umsmng5t4dlwodvmiz4cnc6fl6f' + 'zrvjbfg2ftktrcddan7b3xtgmfge2afbrh4uwam6pfxpq5dbkhbl' + '6mgaijdzpq5efw2ynlnjhoeqyh6dakl4yg346gbhabzkcxreu7hc' + 'jhw6vo6wwa7ky2sjdk742khlgsakwtme6sr2dfkhlxxkcqw3jngy' + 'rq5zj7m6m7hnscuzlzsviawnvg47pe7l4hxiexpbb5k456r' +) + # Protect against local user's .arcrc interference. phabricator.ARCRC = {} + class PhabricatorTest(unittest.TestCase): def setUp(self): self.api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') - self.api.certificate = "fdhcq3zsyijnm4h6gmh43zue5umsmng5t4dlwodvmiz4cnc6fl6f" + \ - "zrvjbfg2ftktrcddan7b3xtgmfge2afbrh4uwam6pfxpq5dbkhbl" + \ - "6mgaijdzpq5efw2ynlnjhoeqyh6dakl4yg346gbhabzkcxreu7hc" + \ - "jhw6vo6wwa7ky2sjdk742khlgsakwtme6sr2dfkhlxxkcqw3jngy" + \ - "rq5zj7m6m7hnscuzlzsviawnvg47pe7l4hxiexpbb5k456r" + self.api.certificate = CERTIFICATE def test_generate_hash(self): token = '12345678' hashed = self.api.generate_hash(token) - self.assertEquals(hashed, 'f8d3bea4e58a2b2967d93d5b307bfa7c693b2e7f') + self.assertEqual(hashed, 'f8d3bea4e58a2b2967d93d5b307bfa7c693b2e7f') - @patch('phabricator.httplib.HTTPConnection') + @mock.patch('phabricator.httplib.HTTPConnection') def test_connect(self, mock_connection): - mock = mock_connection.return_value = Mock() - mock.getresponse.return_value = StringIO(RESPONSES['conduit.connect']) + mock_obj = mock_connection.return_value = mock.Mock() + mock_obj.getresponse.return_value = StringIO(RESPONSES['conduit.connect']) api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') api.connect() - self.assertTrue('sessionKey' in api.conduit.keys()) - self.assertTrue('connectionID' in api.conduit.keys()) + keys = api.conduit.keys() + self.assertIn('sessionKey', keys) + self.assertIn('connectionID', keys) - @patch('phabricator.httplib.HTTPConnection') + @mock.patch('phabricator.httplib.HTTPConnection') def test_user_whoami(self, mock_connection): - mock = mock_connection.return_value = Mock() - mock.getresponse.return_value = StringIO(RESPONSES['user.whoami']) + mock_obj = mock_connection.return_value = mock.Mock() + mock_obj.getresponse.return_value = StringIO(RESPONSES['user.whoami']) api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') api.conduit = True - self.assertEqual('testaccount', api.user.whoami()['userName']) + self.assertEqual(api.user.whoami()['userName'], 'testaccount') - @patch('phabricator.httplib.HTTPConnection') + @mock.patch('phabricator.httplib.HTTPConnection') def test_maniphest_find(self, mock_connection): - mock = mock_connection.return_value = Mock() - mock.getresponse.return_value = StringIO(RESPONSES['maniphest.find']) + mock_obj = mock_connection.return_value = mock.Mock() + mock_obj.getresponse.return_value = StringIO(RESPONSES['maniphest.find']) api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') api.conduit = True - result = api.maniphest.find(ownerphids=["PHID-USER-5022a9389121884ab9db"]) - self.assertEqual(1, len(result)) + result = api.maniphest.find(ownerphids=['PHID-USER-5022a9389121884ab9db']) + self.assertEqual(len(result), 1) # Test iteration - self.assertTrue(isinstance([x for x in result], list)) + self.assertIsInstance([x for x in result], list) # Test getattr - self.assertEqual("3", result["PHID-TASK-4cgpskv6zzys6rp5rvrc"]["status"]) + self.assertEqual(result['PHID-TASK-4cgpskv6zzys6rp5rvrc']['status'], '3') def test_validation(self): self.api.conduit = True + self.assertRaises(ValueError, self.api.differential.find) + with self.assertRaises(ValueError): + self.api.differential.find(query=1) + with self.assertRaises(ValueError): + self.api.differential.find(query='1') + with self.assertRaises(ValueError): + self.api.differential.find(query='1', guids='1') with self.assertRaises(ValueError): - self.assertRaises(ValueError, self.api.differential.find()) - self.assertRaises(ValueError, self.api.differential.find(query=1)) - self.assertRaises(ValueError, self.api.differential.find(query="1")) - self.assertRaises(ValueError, self.api.differential.find(query="1", guids="1")) - self.assertRaises(ValueError, self.api.differential.find(query="1", guids=["1"])) + self.api.differential.find(query='1', guids=['1']) if __name__ == '__main__': diff --git a/setup.py b/setup.py index 1b05c2e..10a29fb 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,17 @@ #!/usr/bin/env python +import sys + from setuptools import setup, find_packages +tests_requires = ['pytest'] + +if sys.version_info[:2] < (2, 7): + tests_requires.append('unittest2') + +if sys.version_info[:2] <= (3, 3): + tests_requires.append('mock') + setup( name='phabricator', version='0.5.0', @@ -12,13 +22,20 @@ packages=find_packages(), zip_safe=False, test_suite='nose.collector', - install_requires=[''], - tests_require=['nose', 'unittest2', 'mock'], + tests_require=tests_requires, include_package_data=True, classifiers=[ 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'Operating System :: OS Independent', - 'Topic :: Software Development' + 'Topic :: Software Development', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', ], ) From d77678f52449386894ffa9e35a5c6a5f2c0b64ad Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 25 Dec 2015 17:37:33 +0200 Subject: [PATCH 07/44] Add TravisCI support --- .travis.yml | 8 ++++++++ README.rst | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e65652f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: python +python: + - "2.7" + - "3.3" + - "3.4" + - "3.5" +install: "pip install ." +script: nosetests diff --git a/README.rst b/README.rst index dff51a5..4c3d28c 100644 --- a/README.rst +++ b/README.rst @@ -1,21 +1,24 @@ python-phabricator ================== +.. image:: https://travis-ci.org/disqus/python-phabricator.png?branch=master + :target: https://travis-ci.org/disqus/python-phabricator + Installation ------------ :: - $ python setup.py install + $ pip install phabricator Usage ----- Use the API by instantiating it, and then calling the method through dotted notation chaining:: - from phabricator import Phabricator - phab = Phabricator() # This will use your ~/.arcrc file - phab.user.whoami() + from phabricator import Phabricator + phab = Phabricator() # This will use your ~/.arcrc file + phab.user.whoami() Parameters are passed as keyword arguments to the resource call:: @@ -29,7 +32,7 @@ Interface out-of-date If Phabricator modifies Conduit and the included ``interfaces.json`` is out-of-date or to make sure to always have the latest interfaces:: - from phabricator import Phabricator - phab = Phabricator() - phab.update_interfaces() - phab.user.whoami() + from phabricator import Phabricator + phab = Phabricator() + phab.update_interfaces() + phab.user.whoami() From 87b9d9642af2175632cf7bae6a98481ce5a2b9bf Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 25 Dec 2015 17:40:36 +0200 Subject: [PATCH 08/44] Remove unused `pytest` dependency and remove `nosetest` from Travis conf --- .travis.yml | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e65652f..ebe4f9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,4 @@ python: - "3.4" - "3.5" install: "pip install ." -script: nosetests +script: "python phabricator/tests.py" diff --git a/setup.py b/setup.py index 10a29fb..a60df1f 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import setup, find_packages -tests_requires = ['pytest'] +tests_requires = [] if sys.version_info[:2] < (2, 7): tests_requires.append('unittest2') From 5e8fc812311a61f5f037309ea9273daad4d9c20d Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 26 Dec 2015 00:39:07 +0200 Subject: [PATCH 09/44] Fix bad merge from #9 --- phabricator/__init__.py | 2 +- phabricator/tests.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 618988f..453ca06 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -328,7 +328,7 @@ def _request(self, **kwargs): def connect(self): if self.token: - self.conduit = { + self._conduit = { 'token': self.token } return diff --git a/phabricator/tests.py b/phabricator/tests.py index 5373feb..30fe98f 100644 --- a/phabricator/tests.py +++ b/phabricator/tests.py @@ -52,7 +52,7 @@ def test_connect(self, mock_connection): api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') api.connect() - keys = api.conduit.keys() + keys = api._conduit.keys() self.assertIn('sessionKey', keys) self.assertIn('connectionID', keys) @@ -62,7 +62,7 @@ def test_user_whoami(self, mock_connection): mock_obj.getresponse.return_value = StringIO(RESPONSES['user.whoami']) api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') - api.conduit = True + api._conduit = True self.assertEqual(api.user.whoami()['userName'], 'testaccount') @@ -72,7 +72,7 @@ def test_maniphest_find(self, mock_connection): mock_obj.getresponse.return_value = StringIO(RESPONSES['maniphest.find']) api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') - api.conduit = True + api._conduit = True result = api.maniphest.find(ownerphids=['PHID-USER-5022a9389121884ab9db']) self.assertEqual(len(result), 1) @@ -84,7 +84,7 @@ def test_maniphest_find(self, mock_connection): self.assertEqual(result['PHID-TASK-4cgpskv6zzys6rp5rvrc']['status'], '3') def test_validation(self): - self.api.conduit = True + self.api._conduit = True self.assertRaises(ValueError, self.api.differential.find) with self.assertRaises(ValueError): From 7d2c2ecb8abfbcdbdd1d6a43c69a417ed64bba93 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 26 Dec 2015 00:54:04 +0200 Subject: [PATCH 10/44] Safer config and interface loading mechanisms using `with open() as f:` --- phabricator/__init__.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 453ca06..7bb6fa5 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -31,29 +31,45 @@ __all__ = ['Phabricator'] -# Default phabricator interfaces -INTERFACES = json.loads(open(os.path.join(os.path.dirname(__file__), 'interfaces.json'), 'r').read()) +ON_WINDOWS = os.name == 'nt' +CURRENT_DIR = os.getcwd() + + +# Default Phabricator interfaces +INTERFACES = {} +with open(os.path.join(os.path.dirname(__file__), 'interfaces.json')) as fobj: + INTERFACES = json.load(fobj) + # Load arc config -ARC_CONFIGS = [ +ARC_CONFIGS = ( # System config - os.path.join(os.environ['ProgramData'], 'Phabricator', 'Arcanist', 'config') if os.name == 'nt' else - os.path.join('/etc', 'arcconfig'), + os.path.join( + os.environ['ProgramData'], + 'Phabricator', + 'Arcanist', + 'config' + ) if ON_WINDOWS else os.path.join('/etc', 'arcconfig'), # User config - os.path.join(os.environ['AppData'] if os.name == 'nt' else os.path.expanduser('~'), '.arcrc'), + os.path.join( + os.environ['AppData'] if ON_WINDOWS else os.path.expanduser('~'), + '.arcrc' + ), # Project config - os.path.join(os.getcwd(), '.arcconfig'), + os.path.join(CURRENT_DIR, '.arcconfig'), # Local project config - os.path.join(os.getcwd(), '.git', 'arc', 'config'), -] + os.path.join(CURRENT_DIR, '.git', 'arc', 'config'), +) ARCRC = {} for conf in ARC_CONFIGS: if os.path.exists(conf): - ARCRC.update(json.load(open(conf, 'r'))) + with open(conf, 'r') as fobj: + ARCRC.update(json.load(fobj)) + # Map Phabricator types to Python types PARAM_TYPE_MAP = { From 9f5a550e372006a39e3423aad551c4015b875b0f Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 26 Dec 2015 01:08:00 +0200 Subject: [PATCH 11/44] Add bad HTTP status (non 200) check for responses (fixes #30) --- phabricator/__init__.py | 7 +++++++ phabricator/tests.py | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 7bb6fa5..f943d9c 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -293,6 +293,13 @@ def validate_kwarg(key, target): # TODO: Use HTTP "method" from interfaces.json conn.request('POST', path, body, headers) response = conn.getresponse() + + # Make sure we got a 2xx response indicating success + if not response.status >= 200 or not response.status < 300: + raise httplib.HTTPException( + 'Bad response status: {0}'.format(response.status) + ) + data = self._parse_response(response.read()) return Result(data['result']) diff --git a/phabricator/tests.py b/phabricator/tests.py index 30fe98f..965a1a8 100644 --- a/phabricator/tests.py +++ b/phabricator/tests.py @@ -37,7 +37,11 @@ class PhabricatorTest(unittest.TestCase): def setUp(self): - self.api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') + self.api = phabricator.Phabricator( + username='test', + certificate='test', + host='http://localhost' + ) self.api.certificate = CERTIFICATE def test_generate_hash(self): @@ -49,8 +53,14 @@ def test_generate_hash(self): def test_connect(self, mock_connection): mock_obj = mock_connection.return_value = mock.Mock() mock_obj.getresponse.return_value = StringIO(RESPONSES['conduit.connect']) + mock_obj.getresponse.return_value.status = 200 + + api = phabricator.Phabricator( + username='test', + certificate='test', + host='http://localhost' + ) - api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') api.connect() keys = api._conduit.keys() self.assertIn('sessionKey', keys) @@ -60,16 +70,39 @@ def test_connect(self, mock_connection): def test_user_whoami(self, mock_connection): mock_obj = mock_connection.return_value = mock.Mock() mock_obj.getresponse.return_value = StringIO(RESPONSES['user.whoami']) + mock_obj.getresponse.return_value.status = 200 - api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') + api = phabricator.Phabricator( + username='test', + certificate='test', + host='http://localhost' + ) api._conduit = True self.assertEqual(api.user.whoami()['userName'], 'testaccount') + @mock.patch('phabricator.httplib.HTTPConnection') + def test_bad_status(self, mock_connection): + mock_obj = mock_connection.return_value = mock.Mock() + mock_obj.getresponse.return_value = mock.Mock() + mock_obj.getresponse.return_value.status = 400 + + api = phabricator.Phabricator( + username='test', + certificate='test', + host='http://localhost' + ) + api._conduit = True + + with self.assertRaises(phabricator.httplib.HTTPException): + api.user.whoami() + + @mock.patch('phabricator.httplib.HTTPConnection') def test_maniphest_find(self, mock_connection): mock_obj = mock_connection.return_value = mock.Mock() mock_obj.getresponse.return_value = StringIO(RESPONSES['maniphest.find']) + mock_obj.getresponse.return_value.status = 200 api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') api._conduit = True From b2e2463bc351f7dab4f61b2e2017efd99f4c67b1 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 26 Dec 2015 17:10:37 +0200 Subject: [PATCH 12/44] Remove deprecated `has_key` usage --- phabricator/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index f943d9c..bcd921f 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -326,7 +326,7 @@ def __init__(self, username=None, certificate=None, host=None, # Set values in ~/.arcrc as defaults if ARCRC: self.host = host if host else ARCRC['hosts'].keys()[0] - if token or ARCRC['hosts'][self.host].has_key('token'): + if token or 'token' in ARCRC['hosts'][self.host]: self.token = token if token else ARCRC['hosts'][self.host]['token'] else: self.username = username if username else ARCRC['hosts'][self.host]['user'] @@ -358,8 +358,12 @@ def connect(self): auth = Resource(api=self, method='conduit', endpoint='connect') - response = auth(user=self.username, host=self.host, - client=self.client, clientVersion=self.clientVersion) + response = auth( + user=self.username, + host=self.host, + client=self.client, + clientVersion=self.clientVersion + ) self._conduit = { 'sessionKey': response.sessionKey, From 040f2730a0b1ebbb12ad17768551df6eb5d8f2fc Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 26 Dec 2015 17:54:24 +0200 Subject: [PATCH 13/44] Refactor initial config step so all defaults are always set (fixes #28) --- phabricator/__init__.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index bcd921f..87781d7 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -177,7 +177,7 @@ def parse_interfaces(interfaces): return dict(parsed_interfaces) -class InterfaceNotDefined(NotImplementedError): +class ConfigurationError(Exception): pass @@ -190,10 +190,6 @@ def __str__(self): return '%s: %s' % (self.code, self.message) -class InvalidAccessToken(APIError): - pass - - class Result(MutableMapping): def __init__(self, response): self.response = response @@ -323,19 +319,19 @@ class Phabricator(Resource): def __init__(self, username=None, certificate=None, host=None, timeout=5, response_format='json', token=None, **kwargs): - # Set values in ~/.arcrc as defaults - if ARCRC: - self.host = host if host else ARCRC['hosts'].keys()[0] - if token or 'token' in ARCRC['hosts'][self.host]: - self.token = token if token else ARCRC['hosts'][self.host]['token'] - else: - self.username = username if username else ARCRC['hosts'][self.host]['user'] - self.certificate = certificate if certificate else ARCRC['hosts'][self.host]['cert'] - else: - self.host = host - self.token = token - self.username = username - self.certificate = certificate + defined_hosts = ARCRC.get('hosts', {}) + + try: + self.host = host if host else defined_hosts.keys()[0] + except IndexError: + raise ConfigurationError("No host found or provided.") + + current_host_config = defined_hosts.get(self.host, {}) + self.token = token if token else current_host_config.get('token') + + if self.token is None: + self.username = username if username else current_host_config.get('user') + self.certificate = certificate if certificate else current_host_config.get('cert') self.timeout = timeout self.response_format = response_format From eee2c81c9f270c736a9d081e0e69e432e0f800be Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sun, 27 Dec 2015 19:54:21 +0200 Subject: [PATCH 14/44] Remove obsolete `enum` type --- phabricator/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 87781d7..e9adc59 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -81,7 +81,6 @@ 'diffid': int, 'diff_id': int, 'id': int, - 'enum': int, # bool types 'bool': bool, From ddd6513a66be24585fcefd1a3b34877b27e74cef Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sun, 27 Dec 2015 19:55:27 +0200 Subject: [PATCH 15/44] Make `Response.__len__` more generic so it can handle `list` responses (fixes #12) --- phabricator/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index e9adc59..6307a36 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -208,7 +208,7 @@ def __iter__(self): return iter(self.response) def __len__(self): - return len(self.response.keys()) + return len(self.response) def __repr__(self): return '<%s: %s>' % (type(self).__name__, repr(self.response)) From 1cbfaa1e81d7921f56d2e3414a6144069c948603 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sun, 27 Dec 2015 21:06:05 +0200 Subject: [PATCH 16/44] Update interfaces.json and refactor type info processing a bit --- phabricator/__init__.py | 62 ++++++++++++++++++++----------------- phabricator/interfaces.json | 2 +- phabricator/tests.py | 2 -- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 6307a36..0f1da88 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -103,7 +103,9 @@ 'type': string_types, } -STR_RE = re.compile(r'([a-zA-Z_]+)') +TYPE_INFO_COMMENT_RE = re.compile(r'\s*\([^)]+\)\s*|,.+$') +TYPE_INFO_SPLITTER_RE = re.compile(r'(\w+(?:<.+>)?)(?:\s+|$)') +TYPE_INFO_RE = re.compile(r'(\w+)(<[^>]+>)?(?:\s+|$)') def map_param_type(param_type): @@ -112,18 +114,20 @@ def map_param_type(param_type): This requires a bit of logic since this isn't standardized. If a type doesn't map, assume str """ - m = STR_RE.match(param_type) - main_type = m.group(0) + main_type, sub_type = TYPE_INFO_RE.match(param_type).groups() if main_type in ('list', 'array'): - info = param_type.replace(' ', '').split('<', 1) - # Handle no sub-type: "required list" - sub_type = info[1] if len(info) > 1 else 'str' + if sub_type is not None: + sub_type = sub_type.strip() + + if not sub_type: + sub_type = 'str' # Handle list of pairs: "optional list>" - sub_match = STR_RE.match(sub_type) - sub_type = sub_match.group(0).lower() + sub_match = TYPE_INFO_RE.match(sub_type) + if sub_match: + sub_type = sub_match.group(0).lower() return [PARAM_TYPE_MAP.setdefault(sub_type, string_types)] @@ -151,25 +155,23 @@ def parse_interfaces(interfaces): method['required'] = {} for name, type_info in iteritems(dict(d['params'])): + # Set the defaults + optionality = 'required' + param_type = 'string' + # Usually in the format: - info_pieces = type_info.split(' ', 1) - - # If optionality isn't specified, assume required - if info_pieces[0] not in ('optional', 'required'): - optionality = 'required' - param_type = info_pieces[0] - # Just make an optional string for "ignored" params - elif info_pieces[0] == 'ignored': - optionality = 'optional' - param_type = 'string' - else: - optionality = info_pieces[0] - param_type = info_pieces[1] - - # This isn't validated by the client - if param_type.startswith('nonempty'): - optionality = 'required' - param_type = param_type[9:] + type_info = TYPE_INFO_COMMENT_RE.sub('', type_info) + info_pieces = TYPE_INFO_SPLITTER_RE.findall(type_info) + for info_piece in info_pieces: + if info_piece in ('optional', 'required'): + optionality = info_piece + elif info_piece == 'ignored': + optionality = 'optional' + param_type = 'string' + elif info_piece == 'nonempty': + optionality = 'required' + else: + param_type = info_piece method[optionality][name] = map_param_type(param_type) @@ -238,8 +240,12 @@ def _request(self, **kwargs): def validate_kwarg(key, target): # Always allow list - if isinstance(key, list): - return all([validate_kwarg(x, target[0]) for x in key]) + if isinstance(target, list): + return ( + isinstance(key, (list, tuple, set)) and + all(validate_kwarg(x, target[0]) for x in key) + ) + return isinstance(key, tuple(target) if isinstance(target, list) else target) for key, val in resource.get('required', {}).items(): diff --git a/phabricator/interfaces.json b/phabricator/interfaces.json index 7163cd4..899bf12 100644 --- a/phabricator/interfaces.json +++ b/phabricator/interfaces.json @@ -1 +1 @@ -{"arcanist.projectinfo":{"params":{"name":"required string"}},"audit.query":{"params":{"auditorPHIDs":"optional list\u003cphid\u003e","commitPHIDs":"optional list\u003cphid\u003e","status":"optional enum\u003c\"status-any\", \"status-open\"\u003e (default = \"status-any\")","offset":"optional int","limit":"optional int (default = 100)"}},"chatlog.query":{"params":{"channels":"optional list\u003cstring\u003e","limit":"optional int (default = 100)"}},"chatlog.record":{"params":{"logs":"required list\u003cdict\u003e"}},"conduit.connect":{"params":{"client":"required string","clientVersion":"required int","clientDescription":"optional string","user":"optional string","authToken":"optional int","authSignature":"optional string","host":"required string"}},"conduit.getcertificate":{"params":{"token":"required string","host":"required string"}},"conduit.ping":{"params":[]},"conduit.query":{"params":[]},"conpherence.createthread":{"params":{"title":"optional string","message":"required string","participantPHIDs":"required list\u003cphids\u003e"}},"conpherence.querythread":{"params":{"ids":"optional array\u003cint\u003e","phids":"optional array\u003cphids\u003e","limit":"optional int","offset":"optional int"}},"conpherence.querytransaction":{"params":{"threadID":"optional int","threadPHID":"optional phid","limit":"optional int","offset":"optional int"}},"conpherence.updatethread":{"params":{"id":"optional int","phid":"optional phid","title":"optional string","message":"optional string","addParticipantPHIDs":"optional list\u003cphids\u003e","removeParticipantPHID":"optional phid"}},"differential.createinline":{"params":{"revisionID":"optional revisionid","diffID":"optional diffid","filePath":"required string","isNewFile":"required bool","lineNumber":"required int","lineLength":"optional int","content":"required string"}},"differential.createrawdiff":{"params":{"diff":"required string"}},"differential.getrevisioncomments":{"params":{"ids":"required list\u003cint\u003e","inlines":"optional bool"}},"differential.close":{"params":{"revisionID":"required int"}},"differential.createcomment":{"params":{"revision_id":"required revisionid","message":"optional string","action":"optional string","silent":"optional bool","attach_inlines":"optional bool"}},"differential.creatediff":{"params":{"changes":"required list\u003cdict\u003e","sourceMachine":"required string","sourcePath":"required string","branch":"required string","bookmark":"optional string","sourceControlSystem":"required enum\u003csvn, git\u003e","sourceControlPath":"required string","sourceControlBaseRevision":"required string","parentRevisionID":"optional revisionid","creationMethod":"optional string","authorPHID":"optional phid","arcanistProject":"optional string","repositoryUUID":"optional string","lintStatus":"required enum\u003cnone, skip, okay, warn, fail, postponed\u003e","unitStatus":"required enum\u003cnone, skip, okay, warn, fail, postponed\u003e"}},"differential.createrevision":{"params":{"user":"ignored","diffid":"required diffid","fields":"required dict"}},"differential.find":{"params":{"query":"required enum\u003copen, committable, revision-ids, phids\u003e","guids":"required nonempty list\u003cguids\u003e"}},"differential.finishpostponedlinters":{"params":{"diffID":"required diffID","linters":"required dict"}},"differential.getalldiffs":{"params":{"revision_ids":"required list\u003cint\u003e"}},"differential.getcommitmessage":{"params":{"revision_id":"optional revision_id","fields":"optional dict\u003cstring, wild\u003e","edit":"optional enum\u003c\"edit\", \"create\"\u003e"}},"differential.getcommitpaths":{"params":{"revision_id":"required int"}},"differential.getdiff":{"params":{"revision_id":"optional id","diff_id":"optional id"}},"differential.getrawdiff":{"params":{"diffID":"required diffID"}},"differential.getrevision":{"params":{"revision_id":"required id"}},"differential.markcommitted":{"params":{"revision_id":"required revision_id"}},"differential.parsecommitmessage":{"params":{"corpus":"required string","partial":"optional bool"}},"differential.query":{"params":{"authors":"optional list\u003cphid\u003e","ccs":"optional list\u003cphid\u003e","reviewers":"optional list\u003cphid\u003e","paths":"optional list\u003cpair\u003ccallsign, path\u003e\u003e","commitHashes":"optional list\u003cpair\u003cenum\u003cgtcm, gttr, hgcm\u003e, string\u003e\u003e","status":"optional enum\u003cstatus-any, status-open, status-accepted, status-closed\u003e","order":"optional enum\u003corder-modified, order-created\u003e","limit":"optional uint","offset":"optional uint","ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","subscribers":"optional list\u003cphid\u003e","responsibleUsers":"optional list\u003cphid\u003e","branches":"optional list\u003cstring\u003e","arcanistProjects":"optional list\u003cstring\u003e"}},"differential.querydiffs":{"params":{"ids":"optional list\u003cuint\u003e","revisionIDs":"optional list\u003cuint\u003e"}},"differential.setdiffproperty":{"params":{"diff_id":"required diff_id","name":"required string","data":"required string"}},"differential.updaterevision":{"params":{"id":"required revisionid","diffid":"required diffid","fields":"required dict","message":"required string"}},"differential.updateunitresults":{"params":{"diff_id":"required diff_id","file":"required string","name":"required string","link":"optional string","result":"required string","message":"required string","coverage":"optional map\u003cstring, string\u003e"}},"diffusion.branchquery":{"params":{"limit":"optional int","offset":"optional int","callsign":"required string","branch":"optional string"}},"diffusion.browsequery":{"params":{"path":"optional string","commit":"optional string","needValidityOnly":"optional bool","callsign":"required string","branch":"optional string"}},"diffusion.commitbranchesquery":{"params":{"commit":"required string","callsign":"required string","branch":"optional string"}},"diffusion.commitparentsquery":{"params":{"commit":"required string","callsign":"required string","branch":"optional string"}},"diffusion.diffquery":{"params":{"path":"required string","commit":"optional string","callsign":"required string","branch":"optional string"}},"diffusion.existsquery":{"params":{"commit":"required string","callsign":"required string","branch":"optional string"}},"diffusion.filecontentquery":{"params":{"path":"required string","commit":"required string","needsBlame":"optional bool","callsign":"required string","branch":"optional string"}},"diffusion.historyquery":{"params":{"commit":"required string","path":"required string","offset":"required int","limit":"required int","needDirectChanges":"optional bool","needChildChanges":"optional bool","callsign":"required string","branch":"optional string"}},"diffusion.lastmodifiedquery":{"params":{"commit":"required string","path":"required string","callsign":"required string","branch":"optional string"}},"diffusion.mergedcommitsquery":{"params":{"commit":"required string","limit":"optional int","callsign":"required string","branch":"optional string"}},"diffusion.rawdiffquery":{"params":{"commit":"required string","path":"optional string","timeout":"optional int","linesOfContext":"optional int","againstCommit":"optional string","callsign":"required string","branch":"optional string"}},"diffusion.readmequery":{"params":{"paths":"required array \u003cstring\u003e","callsign":"required string","branch":"optional string"}},"diffusion.refsquery":{"params":{"commit":"required string","callsign":"required string","branch":"optional string"}},"diffusion.resolverefs":{"params":{"refs":"required list\u003cstring\u003e","callsign":"required string","branch":"optional string"}},"diffusion.searchquery":{"params":{"path":"required string","stableCommitName":"required string","grep":"required string","limit":"optional int","offset":"optional int","callsign":"required string","branch":"optional string"}},"diffusion.tagsquery":{"params":{"names":"optional list\u003cstring\u003e","commit":"optional string","needMessages":"optional bool","offset":"optional int","limit":"optional int","callsign":"required string","branch":"optional string"}},"diffusion.createcomment":{"params":{"phid":"required string","action":"optional string","message":"required string"}},"diffusion.findsymbols":{"params":{"name":"optional string","namePrefix":"optional string","context":"optional string","language":"optional string","type":"optional string"}},"diffusion.getcommits":{"params":{"commits":"required list\u003cstring\u003e"}},"diffusion.getlintmessages":{"params":{"arcanistProject":"required string","branch":"optional string","commit":"optional string","files":"required list\u003cstring\u003e"}},"diffusion.getrecentcommitsbypath":{"params":{"callsign":"required string","path":"required string","branch":"optional string","limit":"optional int"}},"diffusion.looksoon":{"params":{"callsigns":"required list\u003cstring\u003e","urgency":"optional string"}},"feed.publish":{"params":{"type":"required string","data":"required dict","time":"optional int"}},"feed.query":{"params":{"filterPHIDs":"optional list \u003cphid\u003e","limit":"optional int (default 100)","after":"optional int","before":"optional int","view":"optional string (data, html, html-summary, text)"}},"file.download":{"params":{"phid":"required phid"}},"file.info":{"params":{"phid":"optional phid","id":"optional id"}},"file.upload":{"params":{"data_base64":"required nonempty base64-bytes","name":"optional string"}},"file.uploadhash":{"params":{"hash":"required nonempty string","name":"required nonempty string"}},"flag.delete":{"params":{"id":"optional id","objectPHID":"optional phid"}},"flag.edit":{"params":{"objectPHID":"required phid","color":"optional int","note":"optional string"}},"flag.query":{"params":{"ownerPHIDs":"optional list\u003cphid\u003e","types":"optional list\u003ctype\u003e","objectPHIDs":"optional list\u003cphid\u003e","offset":"optional int","limit":"optional int (default = 100)"}},"macro.creatememe":{"params":{"macroName":"string","upperText":"optional string","lowerText":"optional string"}},"macro.query":{"params":{"authorPHIDs":"optional list\u003cphid\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cid\u003e","names":"optional list\u003cstring\u003e","nameLike":"optional string"}},"maniphest.createtask":{"params":{"title":"required string","description":"optional string","ownerPHID":"optional phid","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","filePHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict"}},"maniphest.gettasktransactions":{"params":{"ids":"required list\u003cint\u003e"}},"maniphest.info":{"params":{"task_id":"required id"}},"maniphest.query":{"params":{"ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","ownerPHIDs":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","projectPHIDs":"optional list\u003cphid\u003e","ccPHIDs":"optional list\u003cphid\u003e","fullText":"optional string","status":"optional enum\u003cstatus-any, status-open, status-closed, status-resolved, status-wontfix, status-invalid, status-spite, status-duplicate\u003e","order":"optional enum\u003corder-priority, order-created, order-modified\u003e","limit":"optional int","offset":"optional int"}},"maniphest.find":{"params":{"ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","ownerPHIDs":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","projectPHIDs":"optional list\u003cphid\u003e","ccPHIDs":"optional list\u003cphid\u003e","fullText":"optional string","status":"optional enum\u003cstatus-any, status-open, status-closed, status-resolved, status-wontfix, status-invalid, status-spite, status-duplicate\u003e","order":"optional enum\u003corder-priority, order-created, order-modified\u003e","limit":"optional int","offset":"optional int"}},"maniphest.update":{"params":{"id":"optional int","phid":"optional int","title":"optional string","description":"optional string","ownerPHID":"optional phid","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","filePHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict","status":"optional int","comments":"optional string"}},"owners.query":{"params":{"userOwner":"optional string","projectOwner":"optional string","userAffiliated":"optional string","repositoryCallsign":"optional string","path":"optional string"}},"paste.create":{"params":{"content":"required string","title":"optional string","language":"optional string"}},"paste.info":{"params":{"paste_id":"required id"}},"paste.query":{"params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","after":"optional int","limit":"optional int, default = 100"}},"phame.query":{"params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","after":"optional int","before":"optional int","limit":"optional int"}},"phame.queryposts":{"params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","blogPHIDs":"optional list\u003cphid\u003e","bloggerPHIDs":"optional list\u003cphid\u003e","phameTitles":"optional list\u003cstring\u003e","published":"optional bool","publishedAfter":"optional date","before":"optional int","after":"optional int","limit":"optional int"}},"phid.info":{"params":{"phid":"required phid"}},"phid.lookup":{"params":{"names":"required list\u003cstring\u003e"}},"phid.query":{"params":{"phids":"required list\u003cphid\u003e"}},"phpast.getast":{"params":{"code":"required string"}},"phpast.version":{"params":[]},"phriction.edit":{"params":{"slug":"required string","title":"optional string","content":"optional string","description":"optional string"}},"phriction.history":{"params":{"slug":"required string"}},"phriction.info":{"params":{"slug":"required string"}},"project.query":{"params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","status":"optional enum\u003cstatus-any, status-open, status-closed, status-active, status-archived\u003e","members":"optional list\u003cphid\u003e","limit":"optional int","offset":"optional int"}},"releeph.getbranches":{"params":[]},"releeph.projectinfo":{"params":{"arcProjectName":"optional string"}},"releeph.queryrequests":{"params":{"revisionPHIDs":"optional list\u003cphid\u003e","requestedCommitPHIDs":"optional list\u003cphid\u003e"}},"releeph.request":{"params":{"branchPHID":"required string","things":"required string","fields":"dict\u003cstring, string\u003e"}},"releephwork.canpush":{"params":{"projectPHID":"required string"}},"releephwork.getauthorinfo":{"params":{"userPHID":"required string","vcsType":"required string"}},"releephwork.getbranch":{"params":{"branchPHID":"required string"}},"releephwork.getbranchcommitmessage":{"params":{"branchPHID":"required string"}},"releephwork.getcommitmessage":{"params":{"requestPHID":"required string","action":"required enum\u003c\"pick\", \"revert\"\u003e"}},"releephwork.getorigcommitmessage":{"params":{"commitPHID":"required string"}},"releephwork.nextrequest":{"params":{"branchPHID":"required int","seen":"required list\u003cstring, bool\u003e"}},"releephwork.record":{"params":{"requestPHID":"required string","action":"required enum\u003c\"pick\", \"revert\"\u003e","commitIdentifier":"required string"}},"releephwork.recordpickstatus":{"params":{"requestPHID":"required string","action":"required enum\u003c\"pick\", \"revert\"\u003e","ok":"required bool","dryRun":"optional bool","details":"optional dict\u003cstring, wild\u003e"}},"remarkup.process":{"params":{"context":"required enum\u003cphriction, maniphest, differential, phame, feed, diffusion\u003e","contents":"required list\u003cstring\u003e"}},"repository.create":{"params":{"name":"required string","vcs":"required enum\u003cgit, hg, svn\u003e","callsign":"required string","description":"optional string","encoding":"optional string","tracking":"optional bool","uri":"optional string","sshUser":"optional string","sshKey":"optional string","sshKeyFile":"optional string","httpUser":"optional string","httpPassword":"optional string","localPath":"optional string","svnSubpath":"optional string","branchFilter":"optional list\u003cstring\u003e","closeCommitsFilter":"optional list\u003cstring\u003e","pullFrequency":"optional int","defaultBranch":"optional string","heraldEnabled":"optional bool, default = true","autocloseEnabled":"optional bool, default = true","svnUUID":"optional string"}},"repository.query":{"params":[]},"slowvote.info":{"params":{"poll_id":"required id"}},"token.give":{"params":{"tokenPHID":"phid|null","objectPHID":"phid"}},"token.given":{"params":{"authorPHIDs":"list\u003cphid\u003e","objectPHIDs":"list\u003cphid\u003e","tokenPHIDs":"list\u003cphid\u003e"}},"token.query":{"params":[]},"user.addstatus":{"params":{"fromEpoch":"required int","toEpoch":"required int","status":"required enum\u003caway, sporadic\u003e","description":"optional string"}},"user.disable":{"params":{"phids":"required list\u003cphid\u003e"}},"user.enable":{"params":{"phids":"required list\u003cphid\u003e"}},"user.find":{"params":{"aliases":"required nonempty list\u003cstring\u003e"}},"user.info":{"params":{"phid":"required phid"}},"user.query":{"params":{"usernames":"optional list\u003cstring\u003e","emails":"optional list\u003cstring\u003e","realnames":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cuint\u003e","offset":"optional int","limit":"optional int (default = 100)"}},"user.removestatus":{"params":{"fromEpoch":"required int","toEpoch":"required int"}},"user.whoami":{"params":[]}} +{"almanac.querydevices":{"description":"Query Almanac devices.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cwild\u003e"},"almanac.queryservices":{"description":"Query Almanac services.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cphid\u003e","devicePHIDs":"optional list\u003cphid\u003e","serviceClasses":"optional list\u003cstring\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cwild\u003e"},"audit.query":{"description":"Query audit requests.","params":{"auditorPHIDs":"optional list\u003cphid\u003e","commitPHIDs":"optional list\u003cphid\u003e","status":"optional string-constant\u003c\"audit-status-any\", \"audit-status-open\", \"audit-status-concern\", \"audit-status-accepted\", \"audit-status-partial\"\u003e (default = \"audit-status-any\")","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"auth.querypublickeys":{"description":"Query public keys.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","objectPHIDs":"optional list\u003cphid\u003e","keys":"optional list\u003cstring\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"result-set"},"chatlog.query":{"description":"Retrieve chatter.","params":{"channels":"optional list\u003cstring\u003e","limit":"optional int (default = 100)"},"return":"nonempty list\u003cdict\u003e"},"chatlog.record":{"description":"Record chatter.","params":{"logs":"required list\u003cdict\u003e"},"return":"list\u003cid\u003e"},"conduit.connect":{"description":"Connect a session-based client.","params":{"client":"required string","clientVersion":"required int","clientDescription":"optional string","user":"optional string","authToken":"optional int","authSignature":"optional string","host":"deprecated"},"return":"dict\u003cstring, any\u003e"},"conduit.getcapabilities":{"description":"List capabilities, wire formats, and authentication protocols available on this server.","params":[],"return":"dict\u003cstring, any\u003e"},"conduit.getcertificate":{"description":"Retrieve certificate information for a user.","params":{"token":"required string","host":"required string"},"return":"dict\u003cstring, any\u003e"},"conduit.ping":{"description":"Basic ping for monitoring or a health-check.","params":[],"return":"string"},"conduit.query":{"description":"Returns the parameters of the Conduit methods.","params":[],"return":"dict\u003cdict\u003e"},"conpherence.createthread":{"description":"Create a new conpherence thread.","params":{"title":"optional string","message":"required string","participantPHIDs":"required list\u003cphids\u003e"},"return":"nonempty dict"},"conpherence.querythread":{"description":"Query for Conpherence threads for the logged in user. You can query by IDs or PHIDs for specific Conpherence threads. Otherwise, specify limit and offset to query the most recently updated Conpherences for the logged in user.","params":{"ids":"optional array\u003cint\u003e","phids":"optional array\u003cphids\u003e","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.querytransaction":{"description":"Query for transactions for the logged in user within a specific Conpherence room. You can specify the room by ID or PHID. Otherwise, specify limit and offset to query the most recent transactions within the Conpherence room for the logged in user.","params":{"roomID":"optional int","roomPHID":"optional phid","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.updatethread":{"description":"Update an existing conpherence room.","params":{"id":"optional int","phid":"optional phid","title":"optional string","message":"optional string","addParticipantPHIDs":"optional list\u003cphids\u003e","removeParticipantPHID":"optional phid"},"return":"bool"},"differential.close":{"description":"Close a Differential revision.","params":{"revisionID":"required int"},"return":"void"},"differential.createcomment":{"description":"Add a comment to a Differential revision.","params":{"revision_id":"required revisionid","message":"optional string","action":"optional string","silent":"optional bool","attach_inlines":"optional bool"},"return":"nonempty dict"},"differential.creatediff":{"description":"Create a new Differential diff.","params":{"changes":"required list\u003cdict\u003e","sourceMachine":"required string","sourcePath":"required string","branch":"required string","bookmark":"optional string","sourceControlSystem":"required string-constant\u003c\"svn\", \"git\", \"hg\"\u003e","sourceControlPath":"required string","sourceControlBaseRevision":"required string","creationMethod":"optional string","lintStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","unitStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","repositoryPHID":"optional phid","parentRevisionID":"deprecated","authorPHID":"deprecated","repositoryUUID":"deprecated"},"return":"nonempty dict"},"differential.createinline":{"description":"Add an inline comment to a Differential revision.","params":{"revisionID":"optional revisionid","diffID":"optional diffid","filePath":"required string","isNewFile":"required bool","lineNumber":"required int","lineLength":"optional int","content":"required string"},"return":"nonempty dict"},"differential.createrawdiff":{"description":"Create a new Differential diff from a raw diff source.","params":{"diff":"required string","repositoryPHID":"optional string","viewPolicy":"optional string"},"return":"nonempty dict"},"differential.createrevision":{"description":"Create a new Differential revision.","params":{"user":"ignored","diffid":"required diffid","fields":"required dict"},"return":"nonempty dict"},"differential.getcommitmessage":{"description":"Retrieve Differential commit messages or message templates.","params":{"revision_id":"optional revision_id","fields":"optional dict\u003cstring, wild\u003e","edit":"optional string-constant\u003c\"edit\", \"create\"\u003e"},"return":"nonempty string"},"differential.getcommitpaths":{"description":"Query which paths should be included when committing a Differential revision.","params":{"revision_id":"required int"},"return":"nonempty list\u003cstring\u003e"},"differential.getrawdiff":{"description":"Retrieve a raw diff","params":{"diffID":"required diffID"},"return":"nonempty string"},"differential.parsecommitmessage":{"description":"Parse commit messages for Differential fields.","params":{"corpus":"required string","partial":"optional bool"},"return":"nonempty dict"},"differential.query":{"description":"Query Differential revisions which match certain criteria.","params":{"authors":"optional list\u003cphid\u003e","ccs":"optional list\u003cphid\u003e","reviewers":"optional list\u003cphid\u003e","paths":"optional list\u003cpair\u003ccallsign, path\u003e\u003e","commitHashes":"optional list\u003cpair\u003cstring-constant\u003c\"gtcm\", \"gttr\", \"hgcm\"\u003e, string\u003e\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-accepted\", \"status-closed\"\u003e","order":"optional string-constant\u003c\"order-modified\", \"order-created\"\u003e","limit":"optional uint","offset":"optional uint","ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","subscribers":"optional list\u003cphid\u003e","responsibleUsers":"optional list\u003cphid\u003e","branches":"optional list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"differential.querydiffs":{"description":"Query differential diffs which match certain criteria.","params":{"ids":"optional list\u003cuint\u003e","revisionIDs":"optional list\u003cuint\u003e"},"return":"list\u003cdict\u003e"},"differential.setdiffproperty":{"description":"Attach properties to Differential diffs.","params":{"diff_id":"required diff_id","name":"required string","data":"required string"},"return":"void"},"differential.updaterevision":{"description":"Update a Differential revision.","params":{"id":"required revisionid","diffid":"required diffid","fields":"required dict","message":"required string"},"return":"nonempty dict"},"differential.find":{"description":"Query Differential revisions which match certain criteria.","params":{"query":"required string-constant\u003c\"open\", \"committable\", \"revision-ids\", \"phids\"\u003e","guids":"required nonempty list\u003cguids\u003e"},"return":"nonempty list\u003cdict\u003e"},"differential.getalldiffs":{"description":"Load all diffs for given revisions from Differential.","params":{"revision_ids":"required list\u003cint\u003e"},"return":"dict"},"differential.getdiff":{"description":"Load the content of a diff from Differential by revision ID or diff ID.","params":{"revision_id":"optional id","diff_id":"optional id"},"return":"nonempty dict"},"differential.getrevision":{"description":"Load the content of a revision from Differential.","params":{"revision_id":"required id"},"return":"nonempty dict"},"differential.getrevisioncomments":{"description":"Retrieve Differential Revision Comments.","params":{"ids":"required list\u003cint\u003e","inlines":"optional bool (deprecated)"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"diffusion.findsymbols":{"description":"Retrieve Diffusion symbol information.","params":{"name":"optional string","namePrefix":"optional string","context":"optional string","language":"optional string","type":"optional string","repositoryPHID":"optional string"},"return":"nonempty list\u003cdict\u003e"},"diffusion.getrecentcommitsbypath":{"description":"Get commit identifiers for recent commits affecting a given path.","params":{"callsign":"required string","path":"required string","branch":"optional string","limit":"optional int"},"return":"nonempty list\u003cstring\u003e"},"diffusion.querycommits":{"description":"Retrieve information about commits.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cstring\u003e","repositoryPHID":"optional phid","needMessages":"optional bool","bypassCache":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, dict\u003e"},"diffusion.branchquery":{"description":"Determine what branches exist for a repository.","params":{"closed":"optional bool","limit":"optional int","offset":"optional int","contains":"optional string","callsign":"required string","branch":"optional string"},"return":"list\u003cdict\u003e"},"diffusion.browsequery":{"description":"File(s) information for a repository at an (optional) path and (optional) commit.","params":{"path":"optional string","commit":"optional string","needValidityOnly":"optional bool","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.commitparentsquery":{"description":"Get the commit identifiers for a commit's parent or parents.","params":{"commit":"required string","callsign":"required string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.diffquery":{"description":"Get diff information from a repository for a specific path at an (optional) commit.","params":{"path":"required string","commit":"optional string","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.existsquery":{"description":"Determine if code exists in a version control system.","params":{"commit":"required string","callsign":"required string","branch":"optional string"},"return":"bool"},"diffusion.filecontentquery":{"description":"Retrieve file content from a repository.","params":{"path":"required string","commit":"required string","needsBlame":"optional bool","timeout":"optional int","byteLimit":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.getlintmessages":{"description":"Get lint messages for existing code.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"optional string","files":"required list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"diffusion.historyquery":{"description":"Returns history information for a repository at a specific commit and path.","params":{"commit":"required string","path":"required string","offset":"required int","limit":"required int","needDirectChanges":"optional bool","needChildChanges":"optional bool","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.lastmodifiedquery":{"description":"Get the commits at which paths were last modified.","params":{"paths":"required map\u003cstring, string\u003e","callsign":"required string","branch":"optional string"},"return":"map\u003cstring, string\u003e"},"diffusion.looksoon":{"description":"Advises Phabricator to look for new commits in a repository as soon as possible. This advice is most useful if you have just pushed new commits to that repository.","params":{"callsigns":"required list\u003cstring\u003e","urgency":"optional string"},"return":"void"},"diffusion.mergedcommitsquery":{"description":"Merged commit information for a specific commit in a repository.","params":{"commit":"required string","limit":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.querypaths":{"description":"Filename search on a repository.","params":{"path":"required string","commit":"required string","pattern":"optional string","limit":"optional int","offset":"optional int","callsign":"required string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.rawdiffquery":{"description":"Get raw diff information from a repository for a specific commit at an (optional) path.","params":{"commit":"required string","path":"optional string","timeout":"optional int","byteLimit":"optional int","linesOfContext":"optional int","againstCommit":"optional string","callsign":"required string","branch":"optional string"},"return":"string"},"diffusion.refsquery":{"description":"Query a git repository for ref information at a specific commit.","params":{"commit":"required string","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.resolverefs":{"description":"Resolve references into stable, canonical identifiers.","params":{"refs":"required list\u003cstring\u003e","types":"optional list\u003cstring\u003e","callsign":"required string","branch":"optional string"},"return":"dict\u003cstring, list\u003cdict\u003cstring, wild\u003e\u003e\u003e"},"diffusion.searchquery":{"description":"Search (grep) a repository at a specific path and commit.","params":{"path":"required string","commit":"optional string","grep":"required string","limit":"optional int","offset":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.tagsquery":{"description":"Retrieve information about tags in a repository.","params":{"names":"optional list\u003cstring\u003e","commit":"optional string","needMessages":"optional bool","offset":"optional int","limit":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.updatecoverage":{"description":"Publish coverage information for a repository.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"required string","coverage":"required map\u003cstring, string\u003e","mode":"optional string-constant\u003c\"overwrite\", \"update\"\u003e"},"return":"void"},"diffusion.createcomment":{"description":"Add a comment to a Diffusion commit. By specifying an action of \"concern\", \"accept\", \"resign\", or \"close\", auditing actions can be triggered. Defaults to \"comment\".","params":{"phid":"required string","action":"optional string","message":"required string","silent":"optional bool"},"return":"bool"},"diffusion.getcommits":{"description":"Retrieve Diffusion commit information.","params":{"commits":"required list\u003cstring\u003e"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"feed.publish":{"description":"Publish a story to the feed.","params":{"type":"required string","data":"required dict","time":"optional int"},"return":"nonempty phid"},"feed.query":{"description":"Query the feed for stories","params":{"filterPHIDs":"optional list \u003cphid\u003e","limit":"optional int (default 100)","after":"optional int","before":"optional int","view":"optional string (data, html, html-summary, text)"},"return":"nonempty dict"},"file.allocate":{"description":"Prepare to upload a file.","params":{"name":"string","contentLength":"int","contentHash":"optional string","viewPolicy":"optional string","deleteAfterEpoch":"optional int"},"return":"map\u003cstring, wild\u003e"},"file.download":{"description":"Download a file from the server.","params":{"phid":"required phid"},"return":"nonempty base64-bytes"},"file.info":{"description":"Get information about a file.","params":{"phid":"optional phid","id":"optional id"},"return":"nonempty dict"},"file.querychunks":{"description":"Get information about file chunks.","params":{"filePHID":"phid"},"return":"list\u003cwild\u003e"},"file.upload":{"description":"Upload a file to the server.","params":{"data_base64":"required nonempty base64-bytes","name":"optional string","viewPolicy":"optional valid policy string or \u003cphid\u003e","canCDN":"optional bool"},"return":"nonempty guid"},"file.uploadchunk":{"description":"Upload a chunk of file data to the server.","params":{"filePHID":"phid","byteStart":"int","data":"string","dataEncoding":"string"},"return":"void"},"file.uploadhash":{"description":"Upload a file to the server using content hash.","params":{"hash":"required nonempty string","name":"required nonempty string"},"return":"phid or null"},"flag.delete":{"description":"Clear a flag.","params":{"id":"optional id","objectPHID":"optional phid"},"return":"dict | null"},"flag.edit":{"description":"Create or modify a flag.","params":{"objectPHID":"required phid","color":"optional int","note":"optional string"},"return":"dict"},"flag.query":{"description":"Query flag markers.","params":{"ownerPHIDs":"optional list\u003cphid\u003e","types":"optional list\u003ctype\u003e","objectPHIDs":"optional list\u003cphid\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"harbormaster.createartifact":{"description":"Use this method to attach artifacts to build targets while running builds. Artifacts can be used to carry data through a complex build workflow, provide extra information to users, or store build results.\n\nWhen creating an artifact, you will choose an `artifactType` from this table. These types of artifacts are supported:\n| Artifact Type | Name | Summary |\n|-------------|--------------|--------------|\n| `host` | **Drydock Host** | References a host lease from Drydock. |\n| `working-copy` | **Drydock Working Copy** | References a working copy lease from Drydock. |\n| `file` | **File** | Stores a reference to file data which has been uploaded to Phabricator. |\n| `uri` | **URI** | Stores a URI. |\n\nEach artifact also needs an `artifactKey`, which names the artifact. Finally, you will provide some `artifactData` to fill in the content of the artifact. The data you provide depends on what type of artifact you are creating.\nDrydock Host\n--------------------------\n\nReferences a host lease from Drydock.\n\nCreate an artifact of this type by passing `host` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nDrydock Working Copy\n--------------------------\n\nReferences a working copy lease from Drydock.\n\nCreate an artifact of this type by passing `working-copy` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nFile\n--------------------------\n\nStores a reference to file data which has been uploaded to Phabricator.\n\nCreate an artifact of this type by passing `file` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `filePHID` | \/\/string\/\/ | File to create an artifact from. |\nFor example:\n```lang=json\n{\n \"filePHID\": \"PHID-FILE-abcdefghijklmnopqrst\"\n}\n\n```\nURI\n--------------------------\n\nStores a URI.\n\nWith `ui.external`, you can use this artifact type to add links to build results in an external build system.\n\nCreate an artifact of this type by passing `uri` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `uri` | \/\/string\/\/ | The URI to store. |\n| `name` | \/\/optional string\/\/ | Optional label for this URI. |\n| `ui.external` | \/\/optional bool\/\/ | If true, display this URI in the UI as an link to additional build details in an external build system. |\nFor example:\n```lang=json\n{\n \"uri\": \"https:\/\/buildserver.mycompany.com\/build\/123\/\",\n \"name\": \"View External Build Results\",\n \"ui.external\": true\n}\n\n```","params":{"buildTargetPHID":"phid","artifactKey":"string","artifactType":"string","artifactData":"map\u003cstring, wild\u003e"},"return":"wild"},"harbormaster.queryautotargets":{"description":"Load or create build autotargets.","params":{"objectPHID":"phid","targetKeys":"list\u003cstring\u003e"},"return":"map\u003cstring, phid\u003e"},"harbormaster.querybuildables":{"description":"Query Harbormaster buildables.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildablePHIDs":"optional list\u003cphid\u003e","containerPHIDs":"optional list\u003cphid\u003e","manualBuildables":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.querybuilds":{"description":"Query Harbormaster builds.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildStatuses":"optional list\u003cstring\u003e","buildablePHIDs":"optional list\u003cphid\u003e","buildPlanPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.sendmessage":{"description":"Send a message about the status of a build target to Harbormaster, notifying the application of build results in an external system.\n\nSending Messages\n================\nIf you run external builds, you can use this method to publish build results back into Harbormaster after the external system finishes work or as it makes progress.\n\nThe simplest way to use this method is to call it once after the build finishes with a `pass` or `fail` message. This will record the build result, and continue the next step in the build if the build was waiting for a result.\n\nWhen you send a status message about a build target, you can optionally include detailed `lint` or `unit` results alongside the message. See below for details.\n\nIf you want to report intermediate results but a build hasn't completed yet, you can use the `work` message. This message doesn't have any direct effects, but allows you to send additional data to update the progress of the build target. The target will continue waiting for a completion message, but the UI will update to show the progress which has been made.\n\nMessage Types\n=============\nWhen you send Harbormaster a message, you must include a `type`, which describes the overall state of the build. For example, use `pass` to tell Harbomaster that a build completed successfully.\n\nSupported message types are:\n\n| Type | Description |\n|--------------|--------------|\n| `pass` | Report that the target is complete, and the target has passed. |\n| `fail` | Report that the target is complete, and the target has failed. |\n| `work` | Report that work on the target is ongoing. This message can be used to report partial results during a build. |\n\nUnit Results\n============\nYou can report test results alongside a message. The simplest way to do this is to report all the results alongside a `pass` or `fail` message, but you can also send a `work` message to report intermediate results.\n\nTo provide unit test results, pass a list of results in the `unit` parameter. Each result shoud be a dictionary with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short test name, like \"ExampleTest\". |\n| `result` | \/\/string\/\/ | Result of the test. |\n| `namespace` | \/\/optional string\/\/ | Optional namespace for this test. This is organizational and is often a class or module name, like \"ExampleTestCase\". |\n| `engine` | \/\/optional string\/\/ | Test engine running the test, like \"JavascriptTestEngine\". This primarily prevents collisions between tests with the same name in different test suites (for example, a Javascript test and a Python test). |\n| `duration` | \/\/optional float or int\/\/ | Runtime duration of the test, in seconds. |\n| `path` | \/\/optional string\/\/ | Path to the file where the test is declared, relative to the project root. |\n| `coverage` | \/\/optional map\u003cstring, wild\u003e\/\/ | Coverage information for this test. |\n\nThe `result` parameter recognizes these test results:\n\n| Key | Name | Description |\n|-------------|--------------|--------------|\n| `pass` | **Pass** | The test passed. |\n| `fail` | **Fail** | The test failed. |\n| `skip` | **Skip** | The test was not executed. |\n| `broken` | **Broken** | The test failed in an abnormal or severe way. For example, the harness crashed instead of reporting a failure. |\n| `unsound` | **Unsound** | The test failed, but this change is probably not what broke it. For example, it might have already been failing. |\n\nThis is a simple, valid value for the `unit` parameter. It reports one passing test and one failing test:\n\n\n\n```lang=json\n[\n {\n \"name\": \"PassingTest\",\n \"result\": \"pass\"\n },\n {\n \"name\": \"FailingTest\",\n \"result\": \"fail\"\n }\n]\n```\n\nLint Results\n============\nLike unit test results, you can report lint results alongside a message. The `lint` parameter should contain results as a list of dictionaries with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short message name, like \"Syntax Error\". |\n| `code` | \/\/string\/\/ | Lint message code identifying the type of message, like \"ERR123\". |\n| `severity` | \/\/string\/\/ | Severity of the message. |\n| `path` | \/\/string\/\/ | Path to the file containing the lint message, from the project root. |\n| `line` | \/\/optional int\/\/ | Line number in the file where the text which triggered the message first appears. The first line of the file is line 1, not line 0. |\n| `char` | \/\/optional int\/\/ | Byte position on the line where the text which triggered the message starts. The first byte on the line is byte 1, not byte 0. This position is byte-based (not character-based) because not all lintable files have a valid character encoding. |\n| `description` | \/\/optional string\/\/ | Long explanation of the lint message. |\n\nThe `severity` parameter recognizes these severity levels:\n\n| Key | Name |\n|-------------|--------------|\n| `advice` | **Advice** |\n| `autofix` | **Auto-Fix** |\n| `warning` | **Warning** |\n| `error` | **Error** |\n| `disabled` | **Disabled** |\n\nThis is a simple, valid value for the `lint` parameter. It reports one error and one warning:\n\n```lang=json\n[\n {\n \"name\": \"Syntax Error\",\n \"code\": \"EXAMPLE1\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/example.c\",\n \"line\": 17,\n \"char\": 3\n },\n {\n \"name\": \"Not A Haiku\",\n \"code\": \"EXAMPLE2\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/source.cpp\",\n \"line\": 23,\n \"char\": 1,\n \"description\": \"This function definition is not a haiku.\"\n }\n]\n```\n\n","params":{"buildTargetPHID":"required phid","type":"required string-constant\u003c\"pass\", \"fail\", \"work\"\u003e","unit":"optional list\u003cwild\u003e","lint":"optional list\u003cwild\u003e"},"return":"void"},"macro.query":{"description":"Retrieve image macro information.","params":{"authorPHIDs":"optional list\u003cphid\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cid\u003e","names":"optional list\u003cstring\u003e","nameLike":"optional string"},"return":"list\u003cdict\u003e"},"macro.creatememe":{"description":"Generate a meme.","params":{"macroName":"string","upperText":"optional string","lowerText":"optional string"},"return":"string"},"maniphest.createtask":{"description":"Create a new Maniphest task.","params":{"title":"required string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict"},"return":"nonempty dict"},"maniphest.gettasktransactions":{"description":"Retrieve Maniphest task transactions.","params":{"ids":"required list\u003cint\u003e"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"maniphest.info":{"description":"Retrieve information about a Maniphest task, given its ID.","params":{"task_id":"required id"},"return":"nonempty dict"},"maniphest.query":{"description":"Execute complex searches for Maniphest tasks.","params":{"ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","ownerPHIDs":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","projectPHIDs":"optional list\u003cphid\u003e","ccPHIDs":"optional list\u003cphid\u003e","fullText":"optional string","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-resolved\", \"status-wontfix\", \"status-invalid\", \"status-spite\", \"status-duplicate\"\u003e","order":"optional string-constant\u003c\"order-priority\", \"order-created\", \"order-modified\"\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"maniphest.querystatuses":{"description":"Retrieve information about possible Maniphest task status values.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"maniphest.update":{"description":"Update an existing Maniphest task.","params":{"id":"optional int","phid":"optional int","title":"optional string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict","status":"optional string","comments":"optional string"},"return":"nonempty dict"},"maniphest.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"maniphest.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"nuance.createitem":{"description":"Create a new item.","params":{"requestorPHID":"required string","sourcePHID":"required string","ownerPHID":"optional string"},"return":"nonempty dict"},"owners.query":{"description":"Query for packages by one of the following: repository\/path, packages with a given user or project owner, or packages affiliated with a user (owned by either the user or a project they are a member of.) You should only provide at most one search query.","params":{"userOwner":"optional string","projectOwner":"optional string","userAffiliated":"optional string","repositoryCallsign":"optional string","path":"optional string"},"return":"dict\u003cphid -\u003e dict of package info\u003e"},"owners.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"owners.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"passphrase.query":{"description":"Query credentials.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","needSecrets":"optional bool","needPublicKeys":"optional bool","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"paste.create":{"description":"Create a new paste.","params":{"content":"required string","title":"optional string","language":"optional string"},"return":"nonempty dict"},"paste.query":{"description":"Query Pastes.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","after":"optional int","limit":"optional int, default = 100"},"return":"list\u003cdict\u003e"},"paste.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"paste.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"paste.info":{"description":"Retrieve an array of information about a paste.","params":{"paste_id":"required id"},"return":"nonempty dict"},"phame.createpost":{"description":"Create a phame post.","params":{"blogPHID":"required phid","title":"required string","body":"required string","bloggerPHID":"optional phid","isDraft":"optional bool"},"return":"list\u003cdict\u003e"},"phame.query":{"description":"Query phame blogs.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","after":"optional int","before":"optional int","limit":"optional int"},"return":"list\u003cdict\u003e"},"phame.queryposts":{"description":"Query phame posts.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","blogPHIDs":"optional list\u003cphid\u003e","bloggerPHIDs":"optional list\u003cphid\u003e","published":"optional bool","publishedAfter":"optional date","before":"optional int","after":"optional int","limit":"optional int"},"return":"list\u003cdict\u003e"},"phid.lookup":{"description":"Look up objects by name.","params":{"names":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.query":{"description":"Retrieve information about arbitrary PHIDs.","params":{"phids":"required list\u003cphid\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.info":{"description":"Retrieve information about an arbitrary PHID.","params":{"phid":"required phid"},"return":"nonempty dict\u003cstring, wild\u003e"},"phragment.getpatch":{"description":"Retrieve the patches to apply for a given set of files.","params":{"path":"required string","state":"required dict\u003cstring, string\u003e"},"return":"nonempty dict"},"phragment.queryfragments":{"description":"Query fragments based on their paths.","params":{"paths":"required list\u003cstring\u003e"},"return":"nonempty dict"},"phriction.create":{"description":"Create a Phriction document.","params":{"slug":"required string","title":"required string","content":"required string","description":"optional string"},"return":"nonempty dict"},"phriction.edit":{"description":"Update a Phriction document.","params":{"slug":"required string","title":"optional string","content":"optional string","description":"optional string"},"return":"nonempty dict"},"phriction.history":{"description":"Retrieve history about a Phriction document.","params":{"slug":"required string"},"return":"nonempty list"},"phriction.info":{"description":"Retrieve information about a Phriction document.","params":{"slug":"required string"},"return":"nonempty dict"},"project.create":{"description":"Create a project.","params":{"name":"required string","members":"optional list\u003cphid\u003e","icon":"optional string","color":"optional string","tags":"optional list\u003cstring\u003e"},"return":"dict"},"project.query":{"description":"Execute searches for Projects.","params":{"ids":"optional list\u003cint\u003e","names":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","slugs":"optional list\u003cstring\u003e","icons":"optional list\u003cstring\u003e","colors":"optional list\u003cstring\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-active\", \"status-archived\"\u003e","members":"optional list\u003cphid\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"releeph.getbranches":{"description":"Return information about all active Releeph branches.","params":[],"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"releeph.querybranches":{"description":"Query information about Releeph branches.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","productPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryproducts":{"description":"Query information about Releeph products.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","repositoryPHIDs":"optional list\u003cphid\u003e","isActive":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryrequests":{"description":"Return information about all Releeph requests linked to the given ids.","params":{"revisionPHIDs":"optional list\u003cphid\u003e","requestedCommitPHIDs":"optional list\u003cphid\u003e"},"return":"dict\u003cstring, wild\u003e"},"releeph.request":{"description":"Request a commit or diff to be picked to a branch.","params":{"branchPHID":"required string","things":"required list\u003cstring\u003e","fields":"dict\u003cstring, string\u003e"},"return":"dict\u003cstring, wild\u003e"},"releephwork.canpush":{"description":"Return whether the conduit user is allowed to push.","params":{"projectPHID":"required string"},"return":"bool"},"releephwork.getauthorinfo":{"description":"Return a string to use as the VCS author.","params":{"userPHID":"required string","vcsType":"required string"},"return":"nonempty string"},"releephwork.getbranch":{"description":"Return information to help checkout \/ cut a Releeph branch.","params":{"branchPHID":"required string"},"return":"dict\u003cstring, wild\u003e"},"releephwork.getbranchcommitmessage":{"description":"Get a commit message for committing a Releeph branch.","params":{"branchPHID":"required string"},"return":"nonempty string"},"releephwork.getcommitmessage":{"description":"Get commit message components for building a ReleephRequest commit message.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e"},"return":"dict\u003cstring, string\u003e"},"releephwork.nextrequest":{"description":"Return info required to cut a branch, and pick and revert ReleephRequests.","params":{"branchPHID":"required phid","seen":"required map\u003cstring, bool\u003e"},"return":""},"releephwork.record":{"description":"Record whether we committed a pick or revert to the upstream repository.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","commitIdentifier":"required string"},"return":"void"},"releephwork.recordpickstatus":{"description":"Record whether a pick or revert was successful or not.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","ok":"required bool","dryRun":"optional bool","details":"optional dict\u003cstring, wild\u003e"},"return":""},"remarkup.process":{"description":"Process text through remarkup in Phabricator context.","params":{"context":"required string-constant\u003c\"phriction\", \"maniphest\", \"differential\", \"phame\", \"feed\", \"diffusion\"\u003e","contents":"required list\u003cstring\u003e"},"return":"nonempty dict"},"repository.create":{"description":"Create a new repository.","params":{"name":"required string","vcs":"required string-constant\u003c\"git\", \"hg\", \"svn\"\u003e","callsign":"required string","description":"optional string","encoding":"optional string","tracking":"optional bool","uri":"required string","credentialPHID":"optional string","svnSubpath":"optional string","branchFilter":"optional list\u003cstring\u003e","closeCommitsFilter":"optional list\u003cstring\u003e","pullFrequency":"optional int","defaultBranch":"optional string","heraldEnabled":"optional bool, default = true","autocloseEnabled":"optional bool, default = true","svnUUID":"optional string"},"return":"nonempty dict"},"repository.query":{"description":"Query repositories.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","callsigns":"optional list\u003cstring\u003e","vcsTypes":"optional list\u003cstring\u003e","remoteURIs":"optional list\u003cstring\u003e","uuids":"optional list\u003cstring\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"slowvote.info":{"description":"Retrieve an array of information about a poll.","params":{"poll_id":"required id"},"return":"nonempty dict"},"token.give":{"description":"Give or change a token.","params":{"tokenPHID":"phid|null","objectPHID":"phid"},"return":"void"},"token.given":{"description":"Query tokens given to objects.","params":{"authorPHIDs":"list\u003cphid\u003e","objectPHIDs":"list\u003cphid\u003e","tokenPHIDs":"list\u003cphid\u003e"},"return":"list\u003cdict\u003e"},"token.query":{"description":"Query tokens.","params":[],"return":"list\u003cdict\u003e"},"user.disable":{"description":"Permanently disable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.enable":{"description":"Re-enable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.query":{"description":"Query users.","params":{"usernames":"optional list\u003cstring\u003e","emails":"optional list\u003cstring\u003e","realnames":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cuint\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"user.whoami":{"description":"Retrieve information about the logged-in user.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"user.find":{"description":"Lookup PHIDs by username. Obsoleted by \"user.query\".","params":{"aliases":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, phid\u003e"}} diff --git a/phabricator/tests.py b/phabricator/tests.py index 965a1a8..aaf78ca 100644 --- a/phabricator/tests.py +++ b/phabricator/tests.py @@ -126,8 +126,6 @@ def test_validation(self): self.api.differential.find(query='1') with self.assertRaises(ValueError): self.api.differential.find(query='1', guids='1') - with self.assertRaises(ValueError): - self.api.differential.find(query='1', guids=['1']) if __name__ == '__main__': From 4356dc39f13b0ab32702e02abaf9f0ff29aeaf02 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 29 Dec 2015 16:14:30 +0200 Subject: [PATCH 17/44] Better test structure --- .travis.yml | 2 +- phabricator/tests/__init__.py | 0 phabricator/tests/resources/__init__.py | 0 phabricator/tests/resources/certificate.txt | 1 + phabricator/tests/resources/responses.json | 5 ++ .../{tests.py => tests/test_phabricator.py} | 48 ++++++++++++------- setup.py | 2 +- 7 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 phabricator/tests/__init__.py create mode 100644 phabricator/tests/resources/__init__.py create mode 100644 phabricator/tests/resources/certificate.txt create mode 100644 phabricator/tests/resources/responses.json rename phabricator/{tests.py => tests/test_phabricator.py} (62%) diff --git a/.travis.yml b/.travis.yml index ebe4f9e..707b2ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,4 @@ python: - "3.4" - "3.5" install: "pip install ." -script: "python phabricator/tests.py" +script: "python -m phabricator.tests.test_phabricator" diff --git a/phabricator/tests/__init__.py b/phabricator/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/phabricator/tests/resources/__init__.py b/phabricator/tests/resources/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/phabricator/tests/resources/certificate.txt b/phabricator/tests/resources/certificate.txt new file mode 100644 index 0000000..a3589fd --- /dev/null +++ b/phabricator/tests/resources/certificate.txt @@ -0,0 +1 @@ +fdhcq3zsyijnm4h6gmh43zue5umsmng5t4dlwodvmiz4cnc6fl6fzrvjbfg2ftktrcddan7b3xtgmfge2afbrh4uwam6pfxpq5dbkhbl6mgaijdzpq5efw2ynlnjhoeqyh6dakl4yg346gbhabzkcxreu7hcjhw6vo6wwa7ky2sjdk742khlgsakwtme6sr2dfkhlxxkcqw3jngyrq5zj7m6m7hnscuzlzsviawnvg47pe7l4hxiexpbb5k456r diff --git a/phabricator/tests/resources/responses.json b/phabricator/tests/resources/responses.json new file mode 100644 index 0000000..2bb85e9 --- /dev/null +++ b/phabricator/tests/resources/responses.json @@ -0,0 +1,5 @@ +{ + "conduit.connect": "{\"result\":{\"connectionID\":1759,\"sessionKey\":\"lwvyv7f6hlzb2vawac6reix7ejvjty72svnir6zy\",\"userPHID\":\"PHID-USER-6ij4rnamb2gsfpdkgmny\"},\"error_code\":null,\"error_info\":null}", + "user.whoami": "{\"result\":{\"phid\":\"PHID-USER-6ij4rnamz2gxfpbkamny\",\"userName\":\"testaccount\",\"realName\":\"Test Account\"},\"error_code\":null,\"error_info\":null}", + "maniphest.find": "{\"result\":{\"PHID-TASK-4cgpskv6zzys6rp5rvrc\":{\"id\":\"722\",\"phid\":\"PHID-TASK-4cgpskv6zzys6rp5rvrc\",\"authorPHID\":\"PHID-USER-5022a9389121884ab9db\",\"ownerPHID\":\"PHID-USER-5022a9389121884ab9db\",\"ccPHIDs\":[\"PHID-USER-5022a9389121884ab9db\",\"PHID-USER-ba8aeea1b3fe2853d6bb\"],\"status\":\"3\",\"priority\":\"Needs Triage\",\"title\":\"Relations should be two-way\",\"description\":\"When adding a differential revision you can specify Maniphest Tickets to add the relation. However, this doesnt add the relation from the ticket -> the differently.(This was added via the commit message)\",\"projectPHIDs\":[\"PHID-PROJ-358dbc2e601f7e619232\",\"PHID-PROJ-f58a9ac58c333f106a69\"],\"uri\":\"https://secure.phabricator.com/T722\",\"auxiliary\":[],\"objectName\":\"T722\",\"dateCreated\":\"1325553508\",\"dateModified\":\"1325618490\"}},\"error_code\":null,\"error_info\":null}" +} diff --git a/phabricator/tests.py b/phabricator/tests/test_phabricator.py similarity index 62% rename from phabricator/tests.py rename to phabricator/tests/test_phabricator.py index aaf78ca..4c1a363 100644 --- a/phabricator/tests.py +++ b/phabricator/tests/test_phabricator.py @@ -13,23 +13,23 @@ except ImportError: import mock +from pkg_resources import resource_string +import json import phabricator -RESPONSES = { - 'conduit.connect': '{"result":{"connectionID":1759,"sessionKey":"lwvyv7f6hlzb2vawac6reix7ejvjty72svnir6zy","userPHID":"PHID-USER-6ij4rnamb2gsfpdkgmny"},"error_code":null,"error_info":null}', - 'user.whoami': '{"result":{"phid":"PHID-USER-6ij4rnamz2gxfpbkamny","userName":"testaccount","realName":"Test Account"},"error_code":null,"error_info":null}', - 'maniphest.find': '{"result":{"PHID-TASK-4cgpskv6zzys6rp5rvrc":{"id":"722","phid":"PHID-TASK-4cgpskv6zzys6rp5rvrc","authorPHID":"PHID-USER-5022a9389121884ab9db","ownerPHID":"PHID-USER-5022a9389121884ab9db","ccPHIDs":["PHID-USER-5022a9389121884ab9db","PHID-USER-ba8aeea1b3fe2853d6bb"],"status":"3","priority":"Needs Triage","title":"Relations should be two-way","description":"When adding a differential revision you can specify Maniphest Tickets to add the relation. However, this doesnt add the relation from the ticket -> the differently.(This was added via the commit message)","projectPHIDs":["PHID-PROJ-358dbc2e601f7e619232","PHID-PROJ-f58a9ac58c333f106a69"],"uri":"https:\/\/secure.phabricator.com\/T722","auxiliary":[],"objectName":"T722","dateCreated":"1325553508","dateModified":"1325618490"}},"error_code":null,"error_info":null}' -} - -CERTIFICATE = ( - 'fdhcq3zsyijnm4h6gmh43zue5umsmng5t4dlwodvmiz4cnc6fl6f' - 'zrvjbfg2ftktrcddan7b3xtgmfge2afbrh4uwam6pfxpq5dbkhbl' - '6mgaijdzpq5efw2ynlnjhoeqyh6dakl4yg346gbhabzkcxreu7hc' - 'jhw6vo6wwa7ky2sjdk742khlgsakwtme6sr2dfkhlxxkcqw3jngy' - 'rq5zj7m6m7hnscuzlzsviawnvg47pe7l4hxiexpbb5k456r' +RESPONSES = json.loads( + resource_string( + 'phabricator.tests.resources', + 'responses.json' + ).decode('utf8') ) +CERTIFICATE = resource_string( + 'phabricator.tests.resources', + 'certificate.txt' +).decode('utf8').strip() + # Protect against local user's .arcrc interference. phabricator.ARCRC = {} @@ -52,7 +52,9 @@ def test_generate_hash(self): @mock.patch('phabricator.httplib.HTTPConnection') def test_connect(self, mock_connection): mock_obj = mock_connection.return_value = mock.Mock() - mock_obj.getresponse.return_value = StringIO(RESPONSES['conduit.connect']) + mock_obj.getresponse.return_value = StringIO( + RESPONSES['conduit.connect'] + ) mock_obj.getresponse.return_value.status = 200 api = phabricator.Phabricator( @@ -97,24 +99,34 @@ def test_bad_status(self, mock_connection): with self.assertRaises(phabricator.httplib.HTTPException): api.user.whoami() - @mock.patch('phabricator.httplib.HTTPConnection') def test_maniphest_find(self, mock_connection): mock_obj = mock_connection.return_value = mock.Mock() - mock_obj.getresponse.return_value = StringIO(RESPONSES['maniphest.find']) + mock_obj.getresponse.return_value = StringIO( + RESPONSES['maniphest.find'] + ) mock_obj.getresponse.return_value.status = 200 - api = phabricator.Phabricator(username='test', certificate='test', host='http://localhost') + api = phabricator.Phabricator( + username='test', + certificate='test', + host='http://localhost' + ) api._conduit = True - result = api.maniphest.find(ownerphids=['PHID-USER-5022a9389121884ab9db']) + result = api.maniphest.find( + ownerphids=['PHID-USER-5022a9389121884ab9db'] + ) self.assertEqual(len(result), 1) # Test iteration self.assertIsInstance([x for x in result], list) # Test getattr - self.assertEqual(result['PHID-TASK-4cgpskv6zzys6rp5rvrc']['status'], '3') + self.assertEqual( + result['PHID-TASK-4cgpskv6zzys6rp5rvrc']['status'], + '3' + ) def test_validation(self): self.api._conduit = True diff --git a/setup.py b/setup.py index a60df1f..1e3db6a 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ description='Phabricator API Bindings', packages=find_packages(), zip_safe=False, - test_suite='nose.collector', + test_suite='phabricator.tests.test_phabricator', tests_require=tests_requires, include_package_data=True, classifiers=[ From 20d363fad46ce4a59a8e264a596beaea9f8073d9 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 30 Dec 2015 16:11:35 +0200 Subject: [PATCH 18/44] 0.6.0 --- CHANGES | 9 +++++++++ setup.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 5431e61..89dcd27 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +0.6.0 + +* Python 3 support +* Fix "not JSON serializable" error when not using a token +* Better tests +* Updated interfaces +* Moved `conduit` to `_conduit` so `.conduit` API is available now +* Updated interfaces to the latest Phabricator version + 0.5.0 * Support new style token-based authentication diff --git a/setup.py b/setup.py index 1e3db6a..34d75fc 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name='phabricator', - version='0.5.0', + version='0.6.0', author='DISQUS', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator', From 6c4b8c3aed71f61c319fb0d7a957d3ccb103a055 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 2 Apr 2016 13:00:54 +0200 Subject: [PATCH 19/44] Decode response into UTF-8 string so it can be used as strings --- phabricator/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 0f1da88..d24f69e 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -301,7 +301,13 @@ def validate_kwarg(key, target): 'Bad response status: {0}'.format(response.status) ) - data = self._parse_response(response.read()) + response_data = response.read() + if isinstance(response_data, str): + response = response_data + else: + response = response_data.decode("utf-8") + + data = self._parse_response(response) return Result(data['result']) From 7e80fac6425a0113b5d040e2567dde60f8e1fe6b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 2 Apr 2016 13:01:22 +0200 Subject: [PATCH 20/44] Convert dictionnary keys iterator to list before using index on it --- phabricator/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index d24f69e..7f50fde 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -333,7 +333,7 @@ def __init__(self, username=None, certificate=None, host=None, defined_hosts = ARCRC.get('hosts', {}) try: - self.host = host if host else defined_hosts.keys()[0] + self.host = host if host else list(defined_hosts.keys())[0] except IndexError: raise ConfigurationError("No host found or provided.") From 838398bc69bc2a757f25473f99af7a38e72e487f Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sun, 10 Apr 2016 14:38:37 +0300 Subject: [PATCH 21/44] 0.6.1 --- CHANGES | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 89dcd27..13f6f3d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.6.1 + +* Fix Python 3 related issues + 0.6.0 * Python 3 support diff --git a/setup.py b/setup.py index 34d75fc..8e39305 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name='phabricator', - version='0.6.0', + version='0.6.1', author='DISQUS', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator', From 6e9b43650b52eb21185a09bdd11f6a8f0e66b2a0 Mon Sep 17 00:00:00 2001 From: James Meador Date: Tue, 5 Jul 2016 16:01:01 -0700 Subject: [PATCH 22/44] Fixes #38: Allow for nested methods to support conduit calls such as diffusion.repository.edit --- phabricator/__init__.py | 17 +++++++++++++++-- phabricator/interfaces.json | 2 +- phabricator/tests/test_phabricator.py | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 7f50fde..797c4e6 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -217,18 +217,31 @@ def __repr__(self): class Resource(object): - def __init__(self, api, interface=None, endpoint=None, method=None): + def __init__(self, api, interface=None, endpoint=None, method=None, nested=False): self.api = api self.interface = interface or copy.deepcopy(parse_interfaces(INTERFACES)) self.endpoint = endpoint self.method = method + self.nested = nested def __getattr__(self, attr): if attr in getattr(self, '__dict__'): return getattr(self, attr) interface = self.interface - if attr not in interface: + if self.nested: + attr = "%s.%s" % (self.endpoint, attr) + submethod_exists = False + submethod_match = attr + '.' + for key in interface.keys(): + if key.startswith(submethod_match): + submethod_exists = True + break + if attr not in interface and submethod_exists: + return Resource(self.api, interface, attr, self.endpoint, nested=True) + elif attr not in interface: interface[attr] = {} + if self.nested: + return Resource(self.api, interface[attr], attr, self.method) return Resource(self.api, interface[attr], attr, self.endpoint) def __call__(self, **kwargs): diff --git a/phabricator/interfaces.json b/phabricator/interfaces.json index 899bf12..6d268ee 100644 --- a/phabricator/interfaces.json +++ b/phabricator/interfaces.json @@ -1 +1 @@ -{"almanac.querydevices":{"description":"Query Almanac devices.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cwild\u003e"},"almanac.queryservices":{"description":"Query Almanac services.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cphid\u003e","devicePHIDs":"optional list\u003cphid\u003e","serviceClasses":"optional list\u003cstring\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cwild\u003e"},"audit.query":{"description":"Query audit requests.","params":{"auditorPHIDs":"optional list\u003cphid\u003e","commitPHIDs":"optional list\u003cphid\u003e","status":"optional string-constant\u003c\"audit-status-any\", \"audit-status-open\", \"audit-status-concern\", \"audit-status-accepted\", \"audit-status-partial\"\u003e (default = \"audit-status-any\")","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"auth.querypublickeys":{"description":"Query public keys.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","objectPHIDs":"optional list\u003cphid\u003e","keys":"optional list\u003cstring\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"result-set"},"chatlog.query":{"description":"Retrieve chatter.","params":{"channels":"optional list\u003cstring\u003e","limit":"optional int (default = 100)"},"return":"nonempty list\u003cdict\u003e"},"chatlog.record":{"description":"Record chatter.","params":{"logs":"required list\u003cdict\u003e"},"return":"list\u003cid\u003e"},"conduit.connect":{"description":"Connect a session-based client.","params":{"client":"required string","clientVersion":"required int","clientDescription":"optional string","user":"optional string","authToken":"optional int","authSignature":"optional string","host":"deprecated"},"return":"dict\u003cstring, any\u003e"},"conduit.getcapabilities":{"description":"List capabilities, wire formats, and authentication protocols available on this server.","params":[],"return":"dict\u003cstring, any\u003e"},"conduit.getcertificate":{"description":"Retrieve certificate information for a user.","params":{"token":"required string","host":"required string"},"return":"dict\u003cstring, any\u003e"},"conduit.ping":{"description":"Basic ping for monitoring or a health-check.","params":[],"return":"string"},"conduit.query":{"description":"Returns the parameters of the Conduit methods.","params":[],"return":"dict\u003cdict\u003e"},"conpherence.createthread":{"description":"Create a new conpherence thread.","params":{"title":"optional string","message":"required string","participantPHIDs":"required list\u003cphids\u003e"},"return":"nonempty dict"},"conpherence.querythread":{"description":"Query for Conpherence threads for the logged in user. You can query by IDs or PHIDs for specific Conpherence threads. Otherwise, specify limit and offset to query the most recently updated Conpherences for the logged in user.","params":{"ids":"optional array\u003cint\u003e","phids":"optional array\u003cphids\u003e","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.querytransaction":{"description":"Query for transactions for the logged in user within a specific Conpherence room. You can specify the room by ID or PHID. Otherwise, specify limit and offset to query the most recent transactions within the Conpherence room for the logged in user.","params":{"roomID":"optional int","roomPHID":"optional phid","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.updatethread":{"description":"Update an existing conpherence room.","params":{"id":"optional int","phid":"optional phid","title":"optional string","message":"optional string","addParticipantPHIDs":"optional list\u003cphids\u003e","removeParticipantPHID":"optional phid"},"return":"bool"},"differential.close":{"description":"Close a Differential revision.","params":{"revisionID":"required int"},"return":"void"},"differential.createcomment":{"description":"Add a comment to a Differential revision.","params":{"revision_id":"required revisionid","message":"optional string","action":"optional string","silent":"optional bool","attach_inlines":"optional bool"},"return":"nonempty dict"},"differential.creatediff":{"description":"Create a new Differential diff.","params":{"changes":"required list\u003cdict\u003e","sourceMachine":"required string","sourcePath":"required string","branch":"required string","bookmark":"optional string","sourceControlSystem":"required string-constant\u003c\"svn\", \"git\", \"hg\"\u003e","sourceControlPath":"required string","sourceControlBaseRevision":"required string","creationMethod":"optional string","lintStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","unitStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","repositoryPHID":"optional phid","parentRevisionID":"deprecated","authorPHID":"deprecated","repositoryUUID":"deprecated"},"return":"nonempty dict"},"differential.createinline":{"description":"Add an inline comment to a Differential revision.","params":{"revisionID":"optional revisionid","diffID":"optional diffid","filePath":"required string","isNewFile":"required bool","lineNumber":"required int","lineLength":"optional int","content":"required string"},"return":"nonempty dict"},"differential.createrawdiff":{"description":"Create a new Differential diff from a raw diff source.","params":{"diff":"required string","repositoryPHID":"optional string","viewPolicy":"optional string"},"return":"nonempty dict"},"differential.createrevision":{"description":"Create a new Differential revision.","params":{"user":"ignored","diffid":"required diffid","fields":"required dict"},"return":"nonempty dict"},"differential.getcommitmessage":{"description":"Retrieve Differential commit messages or message templates.","params":{"revision_id":"optional revision_id","fields":"optional dict\u003cstring, wild\u003e","edit":"optional string-constant\u003c\"edit\", \"create\"\u003e"},"return":"nonempty string"},"differential.getcommitpaths":{"description":"Query which paths should be included when committing a Differential revision.","params":{"revision_id":"required int"},"return":"nonempty list\u003cstring\u003e"},"differential.getrawdiff":{"description":"Retrieve a raw diff","params":{"diffID":"required diffID"},"return":"nonempty string"},"differential.parsecommitmessage":{"description":"Parse commit messages for Differential fields.","params":{"corpus":"required string","partial":"optional bool"},"return":"nonempty dict"},"differential.query":{"description":"Query Differential revisions which match certain criteria.","params":{"authors":"optional list\u003cphid\u003e","ccs":"optional list\u003cphid\u003e","reviewers":"optional list\u003cphid\u003e","paths":"optional list\u003cpair\u003ccallsign, path\u003e\u003e","commitHashes":"optional list\u003cpair\u003cstring-constant\u003c\"gtcm\", \"gttr\", \"hgcm\"\u003e, string\u003e\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-accepted\", \"status-closed\"\u003e","order":"optional string-constant\u003c\"order-modified\", \"order-created\"\u003e","limit":"optional uint","offset":"optional uint","ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","subscribers":"optional list\u003cphid\u003e","responsibleUsers":"optional list\u003cphid\u003e","branches":"optional list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"differential.querydiffs":{"description":"Query differential diffs which match certain criteria.","params":{"ids":"optional list\u003cuint\u003e","revisionIDs":"optional list\u003cuint\u003e"},"return":"list\u003cdict\u003e"},"differential.setdiffproperty":{"description":"Attach properties to Differential diffs.","params":{"diff_id":"required diff_id","name":"required string","data":"required string"},"return":"void"},"differential.updaterevision":{"description":"Update a Differential revision.","params":{"id":"required revisionid","diffid":"required diffid","fields":"required dict","message":"required string"},"return":"nonempty dict"},"differential.find":{"description":"Query Differential revisions which match certain criteria.","params":{"query":"required string-constant\u003c\"open\", \"committable\", \"revision-ids\", \"phids\"\u003e","guids":"required nonempty list\u003cguids\u003e"},"return":"nonempty list\u003cdict\u003e"},"differential.getalldiffs":{"description":"Load all diffs for given revisions from Differential.","params":{"revision_ids":"required list\u003cint\u003e"},"return":"dict"},"differential.getdiff":{"description":"Load the content of a diff from Differential by revision ID or diff ID.","params":{"revision_id":"optional id","diff_id":"optional id"},"return":"nonempty dict"},"differential.getrevision":{"description":"Load the content of a revision from Differential.","params":{"revision_id":"required id"},"return":"nonempty dict"},"differential.getrevisioncomments":{"description":"Retrieve Differential Revision Comments.","params":{"ids":"required list\u003cint\u003e","inlines":"optional bool (deprecated)"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"diffusion.findsymbols":{"description":"Retrieve Diffusion symbol information.","params":{"name":"optional string","namePrefix":"optional string","context":"optional string","language":"optional string","type":"optional string","repositoryPHID":"optional string"},"return":"nonempty list\u003cdict\u003e"},"diffusion.getrecentcommitsbypath":{"description":"Get commit identifiers for recent commits affecting a given path.","params":{"callsign":"required string","path":"required string","branch":"optional string","limit":"optional int"},"return":"nonempty list\u003cstring\u003e"},"diffusion.querycommits":{"description":"Retrieve information about commits.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cstring\u003e","repositoryPHID":"optional phid","needMessages":"optional bool","bypassCache":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, dict\u003e"},"diffusion.branchquery":{"description":"Determine what branches exist for a repository.","params":{"closed":"optional bool","limit":"optional int","offset":"optional int","contains":"optional string","callsign":"required string","branch":"optional string"},"return":"list\u003cdict\u003e"},"diffusion.browsequery":{"description":"File(s) information for a repository at an (optional) path and (optional) commit.","params":{"path":"optional string","commit":"optional string","needValidityOnly":"optional bool","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.commitparentsquery":{"description":"Get the commit identifiers for a commit's parent or parents.","params":{"commit":"required string","callsign":"required string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.diffquery":{"description":"Get diff information from a repository for a specific path at an (optional) commit.","params":{"path":"required string","commit":"optional string","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.existsquery":{"description":"Determine if code exists in a version control system.","params":{"commit":"required string","callsign":"required string","branch":"optional string"},"return":"bool"},"diffusion.filecontentquery":{"description":"Retrieve file content from a repository.","params":{"path":"required string","commit":"required string","needsBlame":"optional bool","timeout":"optional int","byteLimit":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.getlintmessages":{"description":"Get lint messages for existing code.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"optional string","files":"required list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"diffusion.historyquery":{"description":"Returns history information for a repository at a specific commit and path.","params":{"commit":"required string","path":"required string","offset":"required int","limit":"required int","needDirectChanges":"optional bool","needChildChanges":"optional bool","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.lastmodifiedquery":{"description":"Get the commits at which paths were last modified.","params":{"paths":"required map\u003cstring, string\u003e","callsign":"required string","branch":"optional string"},"return":"map\u003cstring, string\u003e"},"diffusion.looksoon":{"description":"Advises Phabricator to look for new commits in a repository as soon as possible. This advice is most useful if you have just pushed new commits to that repository.","params":{"callsigns":"required list\u003cstring\u003e","urgency":"optional string"},"return":"void"},"diffusion.mergedcommitsquery":{"description":"Merged commit information for a specific commit in a repository.","params":{"commit":"required string","limit":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.querypaths":{"description":"Filename search on a repository.","params":{"path":"required string","commit":"required string","pattern":"optional string","limit":"optional int","offset":"optional int","callsign":"required string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.rawdiffquery":{"description":"Get raw diff information from a repository for a specific commit at an (optional) path.","params":{"commit":"required string","path":"optional string","timeout":"optional int","byteLimit":"optional int","linesOfContext":"optional int","againstCommit":"optional string","callsign":"required string","branch":"optional string"},"return":"string"},"diffusion.refsquery":{"description":"Query a git repository for ref information at a specific commit.","params":{"commit":"required string","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.resolverefs":{"description":"Resolve references into stable, canonical identifiers.","params":{"refs":"required list\u003cstring\u003e","types":"optional list\u003cstring\u003e","callsign":"required string","branch":"optional string"},"return":"dict\u003cstring, list\u003cdict\u003cstring, wild\u003e\u003e\u003e"},"diffusion.searchquery":{"description":"Search (grep) a repository at a specific path and commit.","params":{"path":"required string","commit":"optional string","grep":"required string","limit":"optional int","offset":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.tagsquery":{"description":"Retrieve information about tags in a repository.","params":{"names":"optional list\u003cstring\u003e","commit":"optional string","needMessages":"optional bool","offset":"optional int","limit":"optional int","callsign":"required string","branch":"optional string"},"return":"array"},"diffusion.updatecoverage":{"description":"Publish coverage information for a repository.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"required string","coverage":"required map\u003cstring, string\u003e","mode":"optional string-constant\u003c\"overwrite\", \"update\"\u003e"},"return":"void"},"diffusion.createcomment":{"description":"Add a comment to a Diffusion commit. By specifying an action of \"concern\", \"accept\", \"resign\", or \"close\", auditing actions can be triggered. Defaults to \"comment\".","params":{"phid":"required string","action":"optional string","message":"required string","silent":"optional bool"},"return":"bool"},"diffusion.getcommits":{"description":"Retrieve Diffusion commit information.","params":{"commits":"required list\u003cstring\u003e"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"feed.publish":{"description":"Publish a story to the feed.","params":{"type":"required string","data":"required dict","time":"optional int"},"return":"nonempty phid"},"feed.query":{"description":"Query the feed for stories","params":{"filterPHIDs":"optional list \u003cphid\u003e","limit":"optional int (default 100)","after":"optional int","before":"optional int","view":"optional string (data, html, html-summary, text)"},"return":"nonempty dict"},"file.allocate":{"description":"Prepare to upload a file.","params":{"name":"string","contentLength":"int","contentHash":"optional string","viewPolicy":"optional string","deleteAfterEpoch":"optional int"},"return":"map\u003cstring, wild\u003e"},"file.download":{"description":"Download a file from the server.","params":{"phid":"required phid"},"return":"nonempty base64-bytes"},"file.info":{"description":"Get information about a file.","params":{"phid":"optional phid","id":"optional id"},"return":"nonempty dict"},"file.querychunks":{"description":"Get information about file chunks.","params":{"filePHID":"phid"},"return":"list\u003cwild\u003e"},"file.upload":{"description":"Upload a file to the server.","params":{"data_base64":"required nonempty base64-bytes","name":"optional string","viewPolicy":"optional valid policy string or \u003cphid\u003e","canCDN":"optional bool"},"return":"nonempty guid"},"file.uploadchunk":{"description":"Upload a chunk of file data to the server.","params":{"filePHID":"phid","byteStart":"int","data":"string","dataEncoding":"string"},"return":"void"},"file.uploadhash":{"description":"Upload a file to the server using content hash.","params":{"hash":"required nonempty string","name":"required nonempty string"},"return":"phid or null"},"flag.delete":{"description":"Clear a flag.","params":{"id":"optional id","objectPHID":"optional phid"},"return":"dict | null"},"flag.edit":{"description":"Create or modify a flag.","params":{"objectPHID":"required phid","color":"optional int","note":"optional string"},"return":"dict"},"flag.query":{"description":"Query flag markers.","params":{"ownerPHIDs":"optional list\u003cphid\u003e","types":"optional list\u003ctype\u003e","objectPHIDs":"optional list\u003cphid\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"harbormaster.createartifact":{"description":"Use this method to attach artifacts to build targets while running builds. Artifacts can be used to carry data through a complex build workflow, provide extra information to users, or store build results.\n\nWhen creating an artifact, you will choose an `artifactType` from this table. These types of artifacts are supported:\n| Artifact Type | Name | Summary |\n|-------------|--------------|--------------|\n| `host` | **Drydock Host** | References a host lease from Drydock. |\n| `working-copy` | **Drydock Working Copy** | References a working copy lease from Drydock. |\n| `file` | **File** | Stores a reference to file data which has been uploaded to Phabricator. |\n| `uri` | **URI** | Stores a URI. |\n\nEach artifact also needs an `artifactKey`, which names the artifact. Finally, you will provide some `artifactData` to fill in the content of the artifact. The data you provide depends on what type of artifact you are creating.\nDrydock Host\n--------------------------\n\nReferences a host lease from Drydock.\n\nCreate an artifact of this type by passing `host` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nDrydock Working Copy\n--------------------------\n\nReferences a working copy lease from Drydock.\n\nCreate an artifact of this type by passing `working-copy` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nFile\n--------------------------\n\nStores a reference to file data which has been uploaded to Phabricator.\n\nCreate an artifact of this type by passing `file` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `filePHID` | \/\/string\/\/ | File to create an artifact from. |\nFor example:\n```lang=json\n{\n \"filePHID\": \"PHID-FILE-abcdefghijklmnopqrst\"\n}\n\n```\nURI\n--------------------------\n\nStores a URI.\n\nWith `ui.external`, you can use this artifact type to add links to build results in an external build system.\n\nCreate an artifact of this type by passing `uri` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `uri` | \/\/string\/\/ | The URI to store. |\n| `name` | \/\/optional string\/\/ | Optional label for this URI. |\n| `ui.external` | \/\/optional bool\/\/ | If true, display this URI in the UI as an link to additional build details in an external build system. |\nFor example:\n```lang=json\n{\n \"uri\": \"https:\/\/buildserver.mycompany.com\/build\/123\/\",\n \"name\": \"View External Build Results\",\n \"ui.external\": true\n}\n\n```","params":{"buildTargetPHID":"phid","artifactKey":"string","artifactType":"string","artifactData":"map\u003cstring, wild\u003e"},"return":"wild"},"harbormaster.queryautotargets":{"description":"Load or create build autotargets.","params":{"objectPHID":"phid","targetKeys":"list\u003cstring\u003e"},"return":"map\u003cstring, phid\u003e"},"harbormaster.querybuildables":{"description":"Query Harbormaster buildables.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildablePHIDs":"optional list\u003cphid\u003e","containerPHIDs":"optional list\u003cphid\u003e","manualBuildables":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.querybuilds":{"description":"Query Harbormaster builds.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildStatuses":"optional list\u003cstring\u003e","buildablePHIDs":"optional list\u003cphid\u003e","buildPlanPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.sendmessage":{"description":"Send a message about the status of a build target to Harbormaster, notifying the application of build results in an external system.\n\nSending Messages\n================\nIf you run external builds, you can use this method to publish build results back into Harbormaster after the external system finishes work or as it makes progress.\n\nThe simplest way to use this method is to call it once after the build finishes with a `pass` or `fail` message. This will record the build result, and continue the next step in the build if the build was waiting for a result.\n\nWhen you send a status message about a build target, you can optionally include detailed `lint` or `unit` results alongside the message. See below for details.\n\nIf you want to report intermediate results but a build hasn't completed yet, you can use the `work` message. This message doesn't have any direct effects, but allows you to send additional data to update the progress of the build target. The target will continue waiting for a completion message, but the UI will update to show the progress which has been made.\n\nMessage Types\n=============\nWhen you send Harbormaster a message, you must include a `type`, which describes the overall state of the build. For example, use `pass` to tell Harbomaster that a build completed successfully.\n\nSupported message types are:\n\n| Type | Description |\n|--------------|--------------|\n| `pass` | Report that the target is complete, and the target has passed. |\n| `fail` | Report that the target is complete, and the target has failed. |\n| `work` | Report that work on the target is ongoing. This message can be used to report partial results during a build. |\n\nUnit Results\n============\nYou can report test results alongside a message. The simplest way to do this is to report all the results alongside a `pass` or `fail` message, but you can also send a `work` message to report intermediate results.\n\nTo provide unit test results, pass a list of results in the `unit` parameter. Each result shoud be a dictionary with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short test name, like \"ExampleTest\". |\n| `result` | \/\/string\/\/ | Result of the test. |\n| `namespace` | \/\/optional string\/\/ | Optional namespace for this test. This is organizational and is often a class or module name, like \"ExampleTestCase\". |\n| `engine` | \/\/optional string\/\/ | Test engine running the test, like \"JavascriptTestEngine\". This primarily prevents collisions between tests with the same name in different test suites (for example, a Javascript test and a Python test). |\n| `duration` | \/\/optional float or int\/\/ | Runtime duration of the test, in seconds. |\n| `path` | \/\/optional string\/\/ | Path to the file where the test is declared, relative to the project root. |\n| `coverage` | \/\/optional map\u003cstring, wild\u003e\/\/ | Coverage information for this test. |\n\nThe `result` parameter recognizes these test results:\n\n| Key | Name | Description |\n|-------------|--------------|--------------|\n| `pass` | **Pass** | The test passed. |\n| `fail` | **Fail** | The test failed. |\n| `skip` | **Skip** | The test was not executed. |\n| `broken` | **Broken** | The test failed in an abnormal or severe way. For example, the harness crashed instead of reporting a failure. |\n| `unsound` | **Unsound** | The test failed, but this change is probably not what broke it. For example, it might have already been failing. |\n\nThis is a simple, valid value for the `unit` parameter. It reports one passing test and one failing test:\n\n\n\n```lang=json\n[\n {\n \"name\": \"PassingTest\",\n \"result\": \"pass\"\n },\n {\n \"name\": \"FailingTest\",\n \"result\": \"fail\"\n }\n]\n```\n\nLint Results\n============\nLike unit test results, you can report lint results alongside a message. The `lint` parameter should contain results as a list of dictionaries with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short message name, like \"Syntax Error\". |\n| `code` | \/\/string\/\/ | Lint message code identifying the type of message, like \"ERR123\". |\n| `severity` | \/\/string\/\/ | Severity of the message. |\n| `path` | \/\/string\/\/ | Path to the file containing the lint message, from the project root. |\n| `line` | \/\/optional int\/\/ | Line number in the file where the text which triggered the message first appears. The first line of the file is line 1, not line 0. |\n| `char` | \/\/optional int\/\/ | Byte position on the line where the text which triggered the message starts. The first byte on the line is byte 1, not byte 0. This position is byte-based (not character-based) because not all lintable files have a valid character encoding. |\n| `description` | \/\/optional string\/\/ | Long explanation of the lint message. |\n\nThe `severity` parameter recognizes these severity levels:\n\n| Key | Name |\n|-------------|--------------|\n| `advice` | **Advice** |\n| `autofix` | **Auto-Fix** |\n| `warning` | **Warning** |\n| `error` | **Error** |\n| `disabled` | **Disabled** |\n\nThis is a simple, valid value for the `lint` parameter. It reports one error and one warning:\n\n```lang=json\n[\n {\n \"name\": \"Syntax Error\",\n \"code\": \"EXAMPLE1\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/example.c\",\n \"line\": 17,\n \"char\": 3\n },\n {\n \"name\": \"Not A Haiku\",\n \"code\": \"EXAMPLE2\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/source.cpp\",\n \"line\": 23,\n \"char\": 1,\n \"description\": \"This function definition is not a haiku.\"\n }\n]\n```\n\n","params":{"buildTargetPHID":"required phid","type":"required string-constant\u003c\"pass\", \"fail\", \"work\"\u003e","unit":"optional list\u003cwild\u003e","lint":"optional list\u003cwild\u003e"},"return":"void"},"macro.query":{"description":"Retrieve image macro information.","params":{"authorPHIDs":"optional list\u003cphid\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cid\u003e","names":"optional list\u003cstring\u003e","nameLike":"optional string"},"return":"list\u003cdict\u003e"},"macro.creatememe":{"description":"Generate a meme.","params":{"macroName":"string","upperText":"optional string","lowerText":"optional string"},"return":"string"},"maniphest.createtask":{"description":"Create a new Maniphest task.","params":{"title":"required string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict"},"return":"nonempty dict"},"maniphest.gettasktransactions":{"description":"Retrieve Maniphest task transactions.","params":{"ids":"required list\u003cint\u003e"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"maniphest.info":{"description":"Retrieve information about a Maniphest task, given its ID.","params":{"task_id":"required id"},"return":"nonempty dict"},"maniphest.query":{"description":"Execute complex searches for Maniphest tasks.","params":{"ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","ownerPHIDs":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","projectPHIDs":"optional list\u003cphid\u003e","ccPHIDs":"optional list\u003cphid\u003e","fullText":"optional string","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-resolved\", \"status-wontfix\", \"status-invalid\", \"status-spite\", \"status-duplicate\"\u003e","order":"optional string-constant\u003c\"order-priority\", \"order-created\", \"order-modified\"\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"maniphest.querystatuses":{"description":"Retrieve information about possible Maniphest task status values.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"maniphest.update":{"description":"Update an existing Maniphest task.","params":{"id":"optional int","phid":"optional int","title":"optional string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict","status":"optional string","comments":"optional string"},"return":"nonempty dict"},"maniphest.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"maniphest.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"nuance.createitem":{"description":"Create a new item.","params":{"requestorPHID":"required string","sourcePHID":"required string","ownerPHID":"optional string"},"return":"nonempty dict"},"owners.query":{"description":"Query for packages by one of the following: repository\/path, packages with a given user or project owner, or packages affiliated with a user (owned by either the user or a project they are a member of.) You should only provide at most one search query.","params":{"userOwner":"optional string","projectOwner":"optional string","userAffiliated":"optional string","repositoryCallsign":"optional string","path":"optional string"},"return":"dict\u003cphid -\u003e dict of package info\u003e"},"owners.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"owners.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"passphrase.query":{"description":"Query credentials.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","needSecrets":"optional bool","needPublicKeys":"optional bool","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"paste.create":{"description":"Create a new paste.","params":{"content":"required string","title":"optional string","language":"optional string"},"return":"nonempty dict"},"paste.query":{"description":"Query Pastes.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","after":"optional int","limit":"optional int, default = 100"},"return":"list\u003cdict\u003e"},"paste.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"paste.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"paste.info":{"description":"Retrieve an array of information about a paste.","params":{"paste_id":"required id"},"return":"nonempty dict"},"phame.createpost":{"description":"Create a phame post.","params":{"blogPHID":"required phid","title":"required string","body":"required string","bloggerPHID":"optional phid","isDraft":"optional bool"},"return":"list\u003cdict\u003e"},"phame.query":{"description":"Query phame blogs.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","after":"optional int","before":"optional int","limit":"optional int"},"return":"list\u003cdict\u003e"},"phame.queryposts":{"description":"Query phame posts.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","blogPHIDs":"optional list\u003cphid\u003e","bloggerPHIDs":"optional list\u003cphid\u003e","published":"optional bool","publishedAfter":"optional date","before":"optional int","after":"optional int","limit":"optional int"},"return":"list\u003cdict\u003e"},"phid.lookup":{"description":"Look up objects by name.","params":{"names":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.query":{"description":"Retrieve information about arbitrary PHIDs.","params":{"phids":"required list\u003cphid\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.info":{"description":"Retrieve information about an arbitrary PHID.","params":{"phid":"required phid"},"return":"nonempty dict\u003cstring, wild\u003e"},"phragment.getpatch":{"description":"Retrieve the patches to apply for a given set of files.","params":{"path":"required string","state":"required dict\u003cstring, string\u003e"},"return":"nonempty dict"},"phragment.queryfragments":{"description":"Query fragments based on their paths.","params":{"paths":"required list\u003cstring\u003e"},"return":"nonempty dict"},"phriction.create":{"description":"Create a Phriction document.","params":{"slug":"required string","title":"required string","content":"required string","description":"optional string"},"return":"nonempty dict"},"phriction.edit":{"description":"Update a Phriction document.","params":{"slug":"required string","title":"optional string","content":"optional string","description":"optional string"},"return":"nonempty dict"},"phriction.history":{"description":"Retrieve history about a Phriction document.","params":{"slug":"required string"},"return":"nonempty list"},"phriction.info":{"description":"Retrieve information about a Phriction document.","params":{"slug":"required string"},"return":"nonempty dict"},"project.create":{"description":"Create a project.","params":{"name":"required string","members":"optional list\u003cphid\u003e","icon":"optional string","color":"optional string","tags":"optional list\u003cstring\u003e"},"return":"dict"},"project.query":{"description":"Execute searches for Projects.","params":{"ids":"optional list\u003cint\u003e","names":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","slugs":"optional list\u003cstring\u003e","icons":"optional list\u003cstring\u003e","colors":"optional list\u003cstring\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-active\", \"status-archived\"\u003e","members":"optional list\u003cphid\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"releeph.getbranches":{"description":"Return information about all active Releeph branches.","params":[],"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"releeph.querybranches":{"description":"Query information about Releeph branches.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","productPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryproducts":{"description":"Query information about Releeph products.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","repositoryPHIDs":"optional list\u003cphid\u003e","isActive":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryrequests":{"description":"Return information about all Releeph requests linked to the given ids.","params":{"revisionPHIDs":"optional list\u003cphid\u003e","requestedCommitPHIDs":"optional list\u003cphid\u003e"},"return":"dict\u003cstring, wild\u003e"},"releeph.request":{"description":"Request a commit or diff to be picked to a branch.","params":{"branchPHID":"required string","things":"required list\u003cstring\u003e","fields":"dict\u003cstring, string\u003e"},"return":"dict\u003cstring, wild\u003e"},"releephwork.canpush":{"description":"Return whether the conduit user is allowed to push.","params":{"projectPHID":"required string"},"return":"bool"},"releephwork.getauthorinfo":{"description":"Return a string to use as the VCS author.","params":{"userPHID":"required string","vcsType":"required string"},"return":"nonempty string"},"releephwork.getbranch":{"description":"Return information to help checkout \/ cut a Releeph branch.","params":{"branchPHID":"required string"},"return":"dict\u003cstring, wild\u003e"},"releephwork.getbranchcommitmessage":{"description":"Get a commit message for committing a Releeph branch.","params":{"branchPHID":"required string"},"return":"nonempty string"},"releephwork.getcommitmessage":{"description":"Get commit message components for building a ReleephRequest commit message.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e"},"return":"dict\u003cstring, string\u003e"},"releephwork.nextrequest":{"description":"Return info required to cut a branch, and pick and revert ReleephRequests.","params":{"branchPHID":"required phid","seen":"required map\u003cstring, bool\u003e"},"return":""},"releephwork.record":{"description":"Record whether we committed a pick or revert to the upstream repository.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","commitIdentifier":"required string"},"return":"void"},"releephwork.recordpickstatus":{"description":"Record whether a pick or revert was successful or not.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","ok":"required bool","dryRun":"optional bool","details":"optional dict\u003cstring, wild\u003e"},"return":""},"remarkup.process":{"description":"Process text through remarkup in Phabricator context.","params":{"context":"required string-constant\u003c\"phriction\", \"maniphest\", \"differential\", \"phame\", \"feed\", \"diffusion\"\u003e","contents":"required list\u003cstring\u003e"},"return":"nonempty dict"},"repository.create":{"description":"Create a new repository.","params":{"name":"required string","vcs":"required string-constant\u003c\"git\", \"hg\", \"svn\"\u003e","callsign":"required string","description":"optional string","encoding":"optional string","tracking":"optional bool","uri":"required string","credentialPHID":"optional string","svnSubpath":"optional string","branchFilter":"optional list\u003cstring\u003e","closeCommitsFilter":"optional list\u003cstring\u003e","pullFrequency":"optional int","defaultBranch":"optional string","heraldEnabled":"optional bool, default = true","autocloseEnabled":"optional bool, default = true","svnUUID":"optional string"},"return":"nonempty dict"},"repository.query":{"description":"Query repositories.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","callsigns":"optional list\u003cstring\u003e","vcsTypes":"optional list\u003cstring\u003e","remoteURIs":"optional list\u003cstring\u003e","uuids":"optional list\u003cstring\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"slowvote.info":{"description":"Retrieve an array of information about a poll.","params":{"poll_id":"required id"},"return":"nonempty dict"},"token.give":{"description":"Give or change a token.","params":{"tokenPHID":"phid|null","objectPHID":"phid"},"return":"void"},"token.given":{"description":"Query tokens given to objects.","params":{"authorPHIDs":"list\u003cphid\u003e","objectPHIDs":"list\u003cphid\u003e","tokenPHIDs":"list\u003cphid\u003e"},"return":"list\u003cdict\u003e"},"token.query":{"description":"Query tokens.","params":[],"return":"list\u003cdict\u003e"},"user.disable":{"description":"Permanently disable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.enable":{"description":"Re-enable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.query":{"description":"Query users.","params":{"usernames":"optional list\u003cstring\u003e","emails":"optional list\u003cstring\u003e","realnames":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cuint\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"user.whoami":{"description":"Retrieve information about the logged-in user.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"user.find":{"description":"Lookup PHIDs by username. Obsoleted by \"user.query\".","params":{"aliases":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, phid\u003e"}} +{"almanac.device.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"almanac.service.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"audit.query":{"description":"Query audit requests.","params":{"auditorPHIDs":"optional list\u003cphid\u003e","commitPHIDs":"optional list\u003cphid\u003e","status":"optional string-constant\u003c\"audit-status-any\", \"audit-status-open\", \"audit-status-concern\", \"audit-status-accepted\", \"audit-status-partial\"\u003e (default = \"audit-status-any\")","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"auth.logout":{"description":"Terminate all web login sessions. If called via OAuth, also terminate the current OAuth token.\n\nWARNING: This method does what it claims on the label. If you call this method via the test console in the web UI, it will log you out!","params":[],"return":"void"},"auth.querypublickeys":{"description":"Query public keys.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","objectPHIDs":"optional list\u003cphid\u003e","keys":"optional list\u003cstring\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"result-set"},"badges.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"badges.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"conduit.connect":{"description":"Connect a session-based client.","params":{"client":"required string","clientVersion":"required int","clientDescription":"optional string","user":"optional string","authToken":"optional int","authSignature":"optional string","host":"deprecated"},"return":"dict\u003cstring, any\u003e"},"conduit.getcapabilities":{"description":"List capabilities, wire formats, and authentication protocols available on this server.","params":[],"return":"dict\u003cstring, any\u003e"},"conduit.getcertificate":{"description":"Retrieve certificate information for a user.","params":{"token":"required string","host":"required string"},"return":"dict\u003cstring, any\u003e"},"conduit.ping":{"description":"Basic ping for monitoring or a health-check.","params":[],"return":"string"},"conduit.query":{"description":"Returns the parameters of the Conduit methods.","params":[],"return":"dict\u003cdict\u003e"},"conpherence.createthread":{"description":"Create a new conpherence thread.","params":{"title":"optional string","message":"required string","participantPHIDs":"required list\u003cphids\u003e"},"return":"nonempty dict"},"conpherence.querythread":{"description":"Query for Conpherence threads for the logged in user. You can query by IDs or PHIDs for specific Conpherence threads. Otherwise, specify limit and offset to query the most recently updated Conpherences for the logged in user.","params":{"ids":"optional array\u003cint\u003e","phids":"optional array\u003cphids\u003e","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.querytransaction":{"description":"Query for transactions for the logged in user within a specific Conpherence room. You can specify the room by ID or PHID. Otherwise, specify limit and offset to query the most recent transactions within the Conpherence room for the logged in user.","params":{"roomID":"optional int","roomPHID":"optional phid","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.updatethread":{"description":"Update an existing conpherence room.","params":{"id":"optional int","phid":"optional phid","title":"optional string","message":"optional string","addParticipantPHIDs":"optional list\u003cphids\u003e","removeParticipantPHID":"optional phid"},"return":"bool"},"dashboard.panel.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"differential.close":{"description":"Close a Differential revision.","params":{"revisionID":"required int"},"return":"void"},"differential.createcomment":{"description":"Add a comment to a Differential revision.","params":{"revision_id":"required revisionid","message":"optional string","action":"optional string","silent":"optional bool","attach_inlines":"optional bool"},"return":"nonempty dict"},"differential.creatediff":{"description":"Create a new Differential diff.","params":{"changes":"required list\u003cdict\u003e","sourceMachine":"required string","sourcePath":"required string","branch":"required string","bookmark":"optional string","sourceControlSystem":"required string-constant\u003c\"svn\", \"git\", \"hg\"\u003e","sourceControlPath":"required string","sourceControlBaseRevision":"required string","creationMethod":"optional string","lintStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","unitStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","repositoryPHID":"optional phid","parentRevisionID":"deprecated","authorPHID":"deprecated","repositoryUUID":"deprecated"},"return":"nonempty dict"},"differential.createinline":{"description":"Add an inline comment to a Differential revision.","params":{"revisionID":"optional revisionid","diffID":"optional diffid","filePath":"required string","isNewFile":"required bool","lineNumber":"required int","lineLength":"optional int","content":"required string"},"return":"nonempty dict"},"differential.createrawdiff":{"description":"Create a new Differential diff from a raw diff source.","params":{"diff":"required string","repositoryPHID":"optional string","viewPolicy":"optional string"},"return":"nonempty dict"},"differential.createrevision":{"description":"Create a new Differential revision.","params":{"user":"ignored","diffid":"required diffid","fields":"required dict"},"return":"nonempty dict"},"differential.getcommitmessage":{"description":"Retrieve Differential commit messages or message templates.","params":{"revision_id":"optional revision_id","fields":"optional dict\u003cstring, wild\u003e","edit":"optional string-constant\u003c\"edit\", \"create\"\u003e"},"return":"nonempty string"},"differential.getcommitpaths":{"description":"Query which paths should be included when committing a Differential revision.","params":{"revision_id":"required int"},"return":"nonempty list\u003cstring\u003e"},"differential.getrawdiff":{"description":"Retrieve a raw diff","params":{"diffID":"required diffID"},"return":"nonempty string"},"differential.parsecommitmessage":{"description":"Parse commit messages for Differential fields.","params":{"corpus":"required string","partial":"optional bool"},"return":"nonempty dict"},"differential.query":{"description":"Query Differential revisions which match certain criteria.","params":{"authors":"optional list\u003cphid\u003e","ccs":"optional list\u003cphid\u003e","reviewers":"optional list\u003cphid\u003e","paths":"optional list\u003cpair\u003ccallsign, path\u003e\u003e","commitHashes":"optional list\u003cpair\u003cstring-constant\u003c\"gtcm\", \"gttr\", \"hgcm\"\u003e, string\u003e\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-accepted\", \"status-closed\"\u003e","order":"optional string-constant\u003c\"order-modified\", \"order-created\"\u003e","limit":"optional uint","offset":"optional uint","ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","subscribers":"optional list\u003cphid\u003e","responsibleUsers":"optional list\u003cphid\u003e","branches":"optional list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"differential.querydiffs":{"description":"Query differential diffs which match certain criteria.","params":{"ids":"optional list\u003cuint\u003e","revisionIDs":"optional list\u003cuint\u003e"},"return":"list\u003cdict\u003e"},"differential.setdiffproperty":{"description":"Attach properties to Differential diffs.","params":{"diff_id":"required diff_id","name":"required string","data":"required string"},"return":"void"},"differential.updaterevision":{"description":"Update a Differential revision.","params":{"id":"required revisionid","diffid":"required diffid","fields":"required dict","message":"required string"},"return":"nonempty dict"},"differential.revision.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"differential.find":{"description":"Query Differential revisions which match certain criteria.","params":{"query":"required string-constant\u003c\"open\", \"committable\", \"revision-ids\", \"phids\"\u003e","guids":"required nonempty list\u003cguids\u003e"},"return":"nonempty list\u003cdict\u003e"},"differential.getalldiffs":{"description":"Load all diffs for given revisions from Differential.","params":{"revision_ids":"required list\u003cint\u003e"},"return":"dict"},"differential.getdiff":{"description":"Load the content of a diff from Differential by revision ID or diff ID.","params":{"revision_id":"optional id","diff_id":"optional id"},"return":"nonempty dict"},"differential.getrevision":{"description":"Load the content of a revision from Differential.","params":{"revision_id":"required id"},"return":"nonempty dict"},"differential.getrevisioncomments":{"description":"Retrieve Differential Revision Comments.","params":{"ids":"required list\u003cint\u003e","inlines":"optional bool (deprecated)"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"diffusion.findsymbols":{"description":"Retrieve Diffusion symbol information.","params":{"name":"optional string","namePrefix":"optional string","context":"optional string","language":"optional string","type":"optional string","repositoryPHID":"optional string"},"return":"nonempty list\u003cdict\u003e"},"diffusion.getrecentcommitsbypath":{"description":"Get commit identifiers for recent commits affecting a given path.","params":{"callsign":"required string","path":"required string","branch":"optional string","limit":"optional int"},"return":"nonempty list\u003cstring\u003e"},"diffusion.querycommits":{"description":"Retrieve information about commits.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cstring\u003e","repositoryPHID":"optional phid","needMessages":"optional bool","bypassCache":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, dict\u003e"},"diffusion.blame":{"description":"Get blame information for a list of paths.","params":{"paths":"required list\u003cstring\u003e","commit":"required string","timeout":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"map\u003cstring, wild\u003e"},"diffusion.branchquery":{"description":"Determine what branches exist for a repository.","params":{"closed":"optional bool","limit":"optional int","offset":"optional int","contains":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cdict\u003e"},"diffusion.browsequery":{"description":"File(s) information for a repository at an (optional) path and (optional) commit.","params":{"path":"optional string","commit":"optional string","needValidityOnly":"optional bool","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.commitparentsquery":{"description":"Get the commit identifiers for a commit's parent or parents.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.diffquery":{"description":"Get diff information from a repository for a specific path at an (optional) commit.","params":{"path":"required string","commit":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.existsquery":{"description":"Determine if code exists in a version control system.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"bool"},"diffusion.filecontentquery":{"description":"Retrieve file content from a repository.","params":{"path":"required string","commit":"required string","timeout":"optional int","byteLimit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.getlintmessages":{"description":"Get lint messages for existing code.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"optional string","files":"required list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"diffusion.historyquery":{"description":"Returns history information for a repository at a specific commit and path.","params":{"commit":"required string","path":"required string","offset":"required int","limit":"required int","needDirectChanges":"optional bool","needChildChanges":"optional bool","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.internal.gitrawdiffquery":{"description":"Internal method for getting raw diff information.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"string"},"diffusion.lastmodifiedquery":{"description":"Get the commits at which paths were last modified.","params":{"paths":"required map\u003cstring, string\u003e","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"map\u003cstring, string\u003e"},"diffusion.looksoon":{"description":"Advises Phabricator to look for new commits in a repository as soon as possible. This advice is most useful if you have just pushed new commits to that repository.","params":{"callsigns":"optional list\u003cstring\u003e (deprecated)","repositories":"optional list\u003cstring\u003e","urgency":"optional string"},"return":"void"},"diffusion.mergedcommitsquery":{"description":"Merged commit information for a specific commit in a repository.","params":{"commit":"required string","limit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.querypaths":{"description":"Filename search on a repository.","params":{"path":"required string","commit":"required string","pattern":"optional string","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.rawdiffquery":{"description":"Get raw diff information from a repository for a specific commit at an (optional) path.","params":{"commit":"required string","path":"optional string","timeout":"optional int","byteLimit":"optional int","linesOfContext":"optional int","againstCommit":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"string"},"diffusion.refsquery":{"description":"Query a git repository for ref information at a specific commit.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.repository.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"diffusion.repository.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"diffusion.resolverefs":{"description":"Resolve references into stable, canonical identifiers.","params":{"refs":"required list\u003cstring\u003e","types":"optional list\u003cstring\u003e","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"dict\u003cstring, list\u003cdict\u003cstring, wild\u003e\u003e\u003e"},"diffusion.searchquery":{"description":"Search (grep) a repository at a specific path and commit.","params":{"path":"required string","commit":"optional string","grep":"required string","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.tagsquery":{"description":"Retrieve information about tags in a repository.","params":{"names":"optional list\u003cstring\u003e","commit":"optional string","needMessages":"optional bool","offset":"optional int","limit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.updatecoverage":{"description":"Publish coverage information for a repository.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"required string","coverage":"required map\u003cstring, string\u003e","mode":"optional string-constant\u003c\"overwrite\", \"update\"\u003e"},"return":"void"},"diffusion.uri.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"diffusion.createcomment":{"description":"Add a comment to a Diffusion commit. By specifying an action of \"concern\", \"accept\", \"resign\", or \"close\", auditing actions can be triggered. Defaults to \"comment\".","params":{"phid":"required string","action":"optional string","message":"required string","silent":"optional bool"},"return":"bool"},"feed.publish":{"description":"Publish a story to the feed.","params":{"type":"required string","data":"required dict","time":"optional int"},"return":"nonempty phid"},"feed.query":{"description":"Query the feed for stories","params":{"filterPHIDs":"optional list \u003cphid\u003e","limit":"optional int (default 100)","after":"optional int","before":"optional int","view":"optional string (data, html, html-summary, text)"},"return":"nonempty dict"},"file.allocate":{"description":"Prepare to upload a file.","params":{"name":"string","contentLength":"int","contentHash":"optional string","viewPolicy":"optional string","deleteAfterEpoch":"optional int"},"return":"map\u003cstring, wild\u003e"},"file.download":{"description":"Download a file from the server.","params":{"phid":"required phid"},"return":"nonempty base64-bytes"},"file.info":{"description":"Get information about a file.","params":{"phid":"optional phid","id":"optional id"},"return":"nonempty dict"},"file.querychunks":{"description":"Get information about file chunks.","params":{"filePHID":"phid"},"return":"list\u003cwild\u003e"},"file.upload":{"description":"Upload a file to the server.","params":{"data_base64":"required nonempty base64-bytes","name":"optional string","viewPolicy":"optional valid policy string or \u003cphid\u003e","canCDN":"optional bool"},"return":"nonempty guid"},"file.uploadchunk":{"description":"Upload a chunk of file data to the server.","params":{"filePHID":"phid","byteStart":"int","data":"string","dataEncoding":"string"},"return":"void"},"file.uploadhash":{"description":"Upload a file to the server using content hash.","params":{"hash":"required nonempty string","name":"required nonempty string"},"return":"phid or null"},"flag.delete":{"description":"Clear a flag.","params":{"id":"optional id","objectPHID":"optional phid"},"return":"dict | null"},"flag.edit":{"description":"Create or modify a flag.","params":{"objectPHID":"required phid","color":"optional int","note":"optional string"},"return":"dict"},"flag.query":{"description":"Query flag markers.","params":{"ownerPHIDs":"optional list\u003cphid\u003e","types":"optional list\u003ctype\u003e","objectPHIDs":"optional list\u003cphid\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"harbormaster.createartifact":{"description":"Use this method to attach artifacts to build targets while running builds. Artifacts can be used to carry data through a complex build workflow, provide extra information to users, or store build results.\n\nWhen creating an artifact, you will choose an `artifactType` from this table. These types of artifacts are supported:\n| Artifact Type | Name | Summary |\n|-------------|--------------|--------------|\n| `host` | **Drydock Host** | References a host lease from Drydock. |\n| `working-copy` | **Drydock Working Copy** | References a working copy lease from Drydock. |\n| `file` | **File** | Stores a reference to file data which has been uploaded to Phabricator. |\n| `uri` | **URI** | Stores a URI. |\n\nEach artifact also needs an `artifactKey`, which names the artifact. Finally, you will provide some `artifactData` to fill in the content of the artifact. The data you provide depends on what type of artifact you are creating.\nDrydock Host\n--------------------------\n\nReferences a host lease from Drydock.\n\nCreate an artifact of this type by passing `host` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nDrydock Working Copy\n--------------------------\n\nReferences a working copy lease from Drydock.\n\nCreate an artifact of this type by passing `working-copy` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nFile\n--------------------------\n\nStores a reference to file data which has been uploaded to Phabricator.\n\nCreate an artifact of this type by passing `file` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `filePHID` | \/\/string\/\/ | File to create an artifact from. |\nFor example:\n```lang=json\n{\n \"filePHID\": \"PHID-FILE-abcdefghijklmnopqrst\"\n}\n\n```\nURI\n--------------------------\n\nStores a URI.\n\nWith `ui.external`, you can use this artifact type to add links to build results in an external build system.\n\nCreate an artifact of this type by passing `uri` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `uri` | \/\/string\/\/ | The URI to store. |\n| `name` | \/\/optional string\/\/ | Optional label for this URI. |\n| `ui.external` | \/\/optional bool\/\/ | If true, display this URI in the UI as an link to additional build details in an external build system. |\nFor example:\n```lang=json\n{\n \"uri\": \"https:\/\/buildserver.mycompany.com\/build\/123\/\",\n \"name\": \"View External Build Results\",\n \"ui.external\": true\n}\n\n```","params":{"buildTargetPHID":"phid","artifactKey":"string","artifactType":"string","artifactData":"map\u003cstring, wild\u003e"},"return":"wild"},"harbormaster.queryautotargets":{"description":"Load or create build autotargets.","params":{"objectPHID":"phid","targetKeys":"list\u003cstring\u003e"},"return":"map\u003cstring, phid\u003e"},"harbormaster.querybuildables":{"description":"Query Harbormaster buildables.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildablePHIDs":"optional list\u003cphid\u003e","containerPHIDs":"optional list\u003cphid\u003e","manualBuildables":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.querybuilds":{"description":"Query Harbormaster builds.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildStatuses":"optional list\u003cstring\u003e","buildablePHIDs":"optional list\u003cphid\u003e","buildPlanPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.sendmessage":{"description":"Send a message about the status of a build target to Harbormaster, notifying the application of build results in an external system.\n\nSending Messages\n================\nIf you run external builds, you can use this method to publish build results back into Harbormaster after the external system finishes work or as it makes progress.\n\nThe simplest way to use this method is to call it once after the build finishes with a `pass` or `fail` message. This will record the build result, and continue the next step in the build if the build was waiting for a result.\n\nWhen you send a status message about a build target, you can optionally include detailed `lint` or `unit` results alongside the message. See below for details.\n\nIf you want to report intermediate results but a build hasn't completed yet, you can use the `work` message. This message doesn't have any direct effects, but allows you to send additional data to update the progress of the build target. The target will continue waiting for a completion message, but the UI will update to show the progress which has been made.\n\nMessage Types\n=============\nWhen you send Harbormaster a message, you must include a `type`, which describes the overall state of the build. For example, use `pass` to tell Harbomaster that a build completed successfully.\n\nSupported message types are:\n\n| Type | Description |\n|--------------|--------------|\n| `pass` | Report that the target is complete, and the target has passed. |\n| `fail` | Report that the target is complete, and the target has failed. |\n| `work` | Report that work on the target is ongoing. This message can be used to report partial results during a build. |\n\nUnit Results\n============\nYou can report test results alongside a message. The simplest way to do this is to report all the results alongside a `pass` or `fail` message, but you can also send a `work` message to report intermediate results.\n\nTo provide unit test results, pass a list of results in the `unit` parameter. Each result shoud be a dictionary with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short test name, like \"ExampleTest\". |\n| `result` | \/\/string\/\/ | Result of the test. |\n| `namespace` | \/\/optional string\/\/ | Optional namespace for this test. This is organizational and is often a class or module name, like \"ExampleTestCase\". |\n| `engine` | \/\/optional string\/\/ | Test engine running the test, like \"JavascriptTestEngine\". This primarily prevents collisions between tests with the same name in different test suites (for example, a Javascript test and a Python test). |\n| `duration` | \/\/optional float or int\/\/ | Runtime duration of the test, in seconds. |\n| `path` | \/\/optional string\/\/ | Path to the file where the test is declared, relative to the project root. |\n| `coverage` | \/\/optional map\u003cstring, wild\u003e\/\/ | Coverage information for this test. |\n| `details` | \/\/optional string\/\/ | Additional human-readable information about the failure. |\n\nThe `result` parameter recognizes these test results:\n\n| Key | Name | Description |\n|-------------|--------------|--------------|\n| `pass` | **Pass** | The test passed. |\n| `fail` | **Fail** | The test failed. |\n| `skip` | **Skip** | The test was not executed. |\n| `broken` | **Broken** | The test failed in an abnormal or severe way. For example, the harness crashed instead of reporting a failure. |\n| `unsound` | **Unsound** | The test failed, but this change is probably not what broke it. For example, it might have already been failing. |\n\nThis is a simple, valid value for the `unit` parameter. It reports one passing test and one failing test:\n\n\n\n```lang=json\n[\n {\n \"name\": \"PassingTest\",\n \"result\": \"pass\"\n },\n {\n \"name\": \"FailingTest\",\n \"result\": \"fail\"\n }\n]\n```\n\nLint Results\n============\nLike unit test results, you can report lint results alongside a message. The `lint` parameter should contain results as a list of dictionaries with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short message name, like \"Syntax Error\". |\n| `code` | \/\/string\/\/ | Lint message code identifying the type of message, like \"ERR123\". |\n| `severity` | \/\/string\/\/ | Severity of the message. |\n| `path` | \/\/string\/\/ | Path to the file containing the lint message, from the project root. |\n| `line` | \/\/optional int\/\/ | Line number in the file where the text which triggered the message first appears. The first line of the file is line 1, not line 0. |\n| `char` | \/\/optional int\/\/ | Byte position on the line where the text which triggered the message starts. The first byte on the line is byte 1, not byte 0. This position is byte-based (not character-based) because not all lintable files have a valid character encoding. |\n| `description` | \/\/optional string\/\/ | Long explanation of the lint message. |\n\nThe `severity` parameter recognizes these severity levels:\n\n| Key | Name |\n|-------------|--------------|\n| `advice` | **Advice** |\n| `autofix` | **Auto-Fix** |\n| `warning` | **Warning** |\n| `error` | **Error** |\n| `disabled` | **Disabled** |\n\nThis is a simple, valid value for the `lint` parameter. It reports one error and one warning:\n\n```lang=json\n[\n {\n \"name\": \"Syntax Error\",\n \"code\": \"EXAMPLE1\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/example.c\",\n \"line\": 17,\n \"char\": 3\n },\n {\n \"name\": \"Not A Haiku\",\n \"code\": \"EXAMPLE2\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/source.cpp\",\n \"line\": 23,\n \"char\": 1,\n \"description\": \"This function definition is not a haiku.\"\n }\n]\n```\n\n","params":{"buildTargetPHID":"required phid","type":"required string-constant\u003c\"pass\", \"fail\", \"work\"\u003e","unit":"optional list\u003cwild\u003e","lint":"optional list\u003cwild\u003e"},"return":"void"},"macro.query":{"description":"Retrieve image macro information.","params":{"authorPHIDs":"optional list\u003cphid\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cid\u003e","names":"optional list\u003cstring\u003e","nameLike":"optional string"},"return":"list\u003cdict\u003e"},"macro.creatememe":{"description":"Generate a meme.","params":{"macroName":"string","upperText":"optional string","lowerText":"optional string"},"return":"string"},"maniphest.createtask":{"description":"Create a new Maniphest task.","params":{"title":"required string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict"},"return":"nonempty dict"},"maniphest.gettasktransactions":{"description":"Retrieve Maniphest task transactions.","params":{"ids":"required list\u003cint\u003e"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"maniphest.info":{"description":"Retrieve information about a Maniphest task, given its ID.","params":{"task_id":"required id"},"return":"nonempty dict"},"maniphest.query":{"description":"Execute complex searches for Maniphest tasks.","params":{"ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","ownerPHIDs":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","projectPHIDs":"optional list\u003cphid\u003e","ccPHIDs":"optional list\u003cphid\u003e","fullText":"optional string","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-resolved\", \"status-wontfix\", \"status-invalid\", \"status-spite\", \"status-duplicate\"\u003e","order":"optional string-constant\u003c\"order-priority\", \"order-created\", \"order-modified\"\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"maniphest.querystatuses":{"description":"Retrieve information about possible Maniphest task status values.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"maniphest.update":{"description":"Update an existing Maniphest task.","params":{"id":"optional int","phid":"optional int","title":"optional string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict","status":"optional string","comments":"optional string"},"return":"nonempty dict"},"maniphest.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"maniphest.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"owners.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"owners.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"owners.query":{"description":"Query for Owners packages. Obsoleted by \"owners.search\".","params":{"userOwner":"optional string","projectOwner":"optional string","userAffiliated":"optional string","repositoryCallsign":"optional string","path":"optional string"},"return":"dict\u003cphid -\u003e dict of package info\u003e"},"passphrase.query":{"description":"Query credentials.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","needSecrets":"optional bool","needPublicKeys":"optional bool","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"paste.create":{"description":"Create a new paste.","params":{"content":"required string","title":"optional string","language":"optional string"},"return":"nonempty dict"},"paste.query":{"description":"Query Pastes.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","after":"optional int","limit":"optional int, default = 100"},"return":"list\u003cdict\u003e"},"paste.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"paste.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"paste.info":{"description":"Retrieve an array of information about a paste.","params":{"paste_id":"required id"},"return":"nonempty dict"},"phame.blog.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"phame.blog.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"phame.post.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"phame.post.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"phid.lookup":{"description":"Look up objects by name.","params":{"names":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.query":{"description":"Retrieve information about arbitrary PHIDs.","params":{"phids":"required list\u003cphid\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.info":{"description":"Retrieve information about an arbitrary PHID.","params":{"phid":"required phid"},"return":"nonempty dict\u003cstring, wild\u003e"},"phragment.getpatch":{"description":"Retrieve the patches to apply for a given set of files.","params":{"path":"required string","state":"required dict\u003cstring, string\u003e"},"return":"nonempty dict"},"phragment.queryfragments":{"description":"Query fragments based on their paths.","params":{"paths":"required list\u003cstring\u003e"},"return":"nonempty dict"},"phriction.create":{"description":"Create a Phriction document.","params":{"slug":"required string","title":"required string","content":"required string","description":"optional string"},"return":"nonempty dict"},"phriction.edit":{"description":"Update a Phriction document.","params":{"slug":"required string","title":"optional string","content":"optional string","description":"optional string"},"return":"nonempty dict"},"phriction.history":{"description":"Retrieve history about a Phriction document.","params":{"slug":"required string"},"return":"nonempty list"},"phriction.info":{"description":"Retrieve information about a Phriction document.","params":{"slug":"required string"},"return":"nonempty dict"},"project.create":{"description":"Create a project.","params":{"name":"required string","members":"optional list\u003cphid\u003e","icon":"optional string","color":"optional string","tags":"optional list\u003cstring\u003e"},"return":"dict"},"project.query":{"description":"Execute searches for Projects.","params":{"ids":"optional list\u003cint\u003e","names":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","slugs":"optional list\u003cstring\u003e","icons":"optional list\u003cstring\u003e","colors":"optional list\u003cstring\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-active\", \"status-archived\"\u003e","members":"optional list\u003cphid\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"project.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"project.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"releeph.getbranches":{"description":"Return information about all active Releeph branches.","params":[],"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"releeph.querybranches":{"description":"Query information about Releeph branches.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","productPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryproducts":{"description":"Query information about Releeph products.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","repositoryPHIDs":"optional list\u003cphid\u003e","isActive":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryrequests":{"description":"Return information about all Releeph requests linked to the given ids.","params":{"revisionPHIDs":"optional list\u003cphid\u003e","requestedCommitPHIDs":"optional list\u003cphid\u003e"},"return":"dict\u003cstring, wild\u003e"},"releeph.request":{"description":"Request a commit or diff to be picked to a branch.","params":{"branchPHID":"required string","things":"required list\u003cstring\u003e","fields":"dict\u003cstring, string\u003e"},"return":"dict\u003cstring, wild\u003e"},"releephwork.canpush":{"description":"Return whether the conduit user is allowed to push.","params":{"projectPHID":"required string"},"return":"bool"},"releephwork.getauthorinfo":{"description":"Return a string to use as the VCS author.","params":{"userPHID":"required string","vcsType":"required string"},"return":"nonempty string"},"releephwork.getbranch":{"description":"Return information to help checkout \/ cut a Releeph branch.","params":{"branchPHID":"required string"},"return":"dict\u003cstring, wild\u003e"},"releephwork.getbranchcommitmessage":{"description":"Get a commit message for committing a Releeph branch.","params":{"branchPHID":"required string"},"return":"nonempty string"},"releephwork.getcommitmessage":{"description":"Get commit message components for building a ReleephRequest commit message.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e"},"return":"dict\u003cstring, string\u003e"},"releephwork.nextrequest":{"description":"Return info required to cut a branch, and pick and revert ReleephRequests.","params":{"branchPHID":"required phid","seen":"required map\u003cstring, bool\u003e"},"return":""},"releephwork.record":{"description":"Record whether we committed a pick or revert to the upstream repository.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","commitIdentifier":"required string"},"return":"void"},"releephwork.recordpickstatus":{"description":"Record whether a pick or revert was successful or not.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","ok":"required bool","dryRun":"optional bool","details":"optional dict\u003cstring, wild\u003e"},"return":""},"remarkup.process":{"description":"Process text through remarkup in Phabricator context.","params":{"context":"required string-constant\u003c\"phriction\", \"maniphest\", \"differential\", \"phame\", \"feed\", \"diffusion\"\u003e","contents":"required list\u003cstring\u003e"},"return":"nonempty dict"},"repository.query":{"description":"Query repositories.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","callsigns":"optional list\u003cstring\u003e","vcsTypes":"optional list\u003cstring\u003e","remoteURIs":"optional list\u003cstring\u003e","uuids":"optional list\u003cstring\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"slowvote.info":{"description":"Retrieve an array of information about a poll.","params":{"poll_id":"required id"},"return":"nonempty dict"},"token.give":{"description":"Give or change a token.","params":{"tokenPHID":"phid|null","objectPHID":"phid"},"return":"void"},"token.given":{"description":"Query tokens given to objects.","params":{"authorPHIDs":"list\u003cphid\u003e","objectPHIDs":"list\u003cphid\u003e","tokenPHIDs":"list\u003cphid\u003e"},"return":"list\u003cdict\u003e"},"token.query":{"description":"Query tokens.","params":[],"return":"list\u003cdict\u003e"},"user.disable":{"description":"Permanently disable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.enable":{"description":"Re-enable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.query":{"description":"Query users.","params":{"usernames":"optional list\u003cstring\u003e","emails":"optional list\u003cstring\u003e","realnames":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cuint\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"user.whoami":{"description":"Retrieve information about the logged-in user.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"user.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"user.find":{"description":"Lookup PHIDs by username. Obsoleted by \"user.query\".","params":{"aliases":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, phid\u003e"}} \ No newline at end of file diff --git a/phabricator/tests/test_phabricator.py b/phabricator/tests/test_phabricator.py index 4c1a363..dc9e4cb 100644 --- a/phabricator/tests/test_phabricator.py +++ b/phabricator/tests/test_phabricator.py @@ -83,6 +83,26 @@ def test_user_whoami(self, mock_connection): self.assertEqual(api.user.whoami()['userName'], 'testaccount') + def test_classic_resources(self): + api = phabricator.Phabricator( + username='test', + certificate='test', + host='http://localhost' + ) + + self.assertEqual(api.user.whoami.method, 'user') + self.assertEqual(api.user.whoami.endpoint, 'whoami') + + def test_nested_resources(self): + api = phabricator.Phabricator( + username='test', + certificate='test', + host='http://localhost' + ) + + self.assertEqual(api.diffusion.repository.edit.method, 'diffusion') + self.assertEqual(api.diffusion.repository.edit.endpoint, 'repository.edit') + @mock.patch('phabricator.httplib.HTTPConnection') def test_bad_status(self, mock_connection): mock_obj = mock_connection.return_value = mock.Mock() From c9c1356e17f43314bfc805ae5f53d03f45928f00 Mon Sep 17 00:00:00 2001 From: James Meador Date: Tue, 5 Jul 2016 23:57:31 -0700 Subject: [PATCH 23/44] Fixes #37,#39: Fix Regex bugs causing incorrect type detection and validation failures --- phabricator/__init__.py | 6 +++--- phabricator/tests/test_phabricator.py | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 7f50fde..ad989ea 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -103,9 +103,9 @@ 'type': string_types, } -TYPE_INFO_COMMENT_RE = re.compile(r'\s*\([^)]+\)\s*|,.+$') +TYPE_INFO_COMMENT_RE = re.compile(r'\s*\([^)]+\)\s*$') TYPE_INFO_SPLITTER_RE = re.compile(r'(\w+(?:<.+>)?)(?:\s+|$)') -TYPE_INFO_RE = re.compile(r'(\w+)(<[^>]+>)?(?:\s+|$)') +TYPE_INFO_RE = re.compile(r']+>>?)?(?:.+|$)') def map_param_type(param_type): @@ -127,7 +127,7 @@ def map_param_type(param_type): # Handle list of pairs: "optional list>" sub_match = TYPE_INFO_RE.match(sub_type) if sub_match: - sub_type = sub_match.group(0).lower() + sub_type = sub_match.group(1).lower() return [PARAM_TYPE_MAP.setdefault(sub_type, string_types)] diff --git a/phabricator/tests/test_phabricator.py b/phabricator/tests/test_phabricator.py index 4c1a363..d342c60 100644 --- a/phabricator/tests/test_phabricator.py +++ b/phabricator/tests/test_phabricator.py @@ -139,6 +139,18 @@ def test_validation(self): with self.assertRaises(ValueError): self.api.differential.find(query='1', guids='1') + def test_map_param_type(self): + uint = 'uint' + self.assertEqual(phabricator.map_param_type(uint), int) + + list_bool = 'list' + self.assertEqual(phabricator.map_param_type(list_bool), [bool]) + + list_pair = 'list>' + self.assertEqual(phabricator.map_param_type(list_pair), [tuple]) + + complex_list_pair = 'list, string>>' + self.assertEqual(phabricator.map_param_type(complex_list_pair), [tuple]) if __name__ == '__main__': unittest.main() From 78b9e85104b27b5ee904605d5a53ed3da903241b Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 8 Jul 2016 18:34:45 +0300 Subject: [PATCH 24/44] Add auto deploy with TravisCI --- .travis.yml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 707b2ca..80deb19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,15 @@ -language: python -python: - - "2.7" - - "3.3" - - "3.4" - - "3.5" -install: "pip install ." -script: "python -m phabricator.tests.test_phabricator" +language: python +python: +- '2.7' +- '3.3' +- '3.4' +- '3.5' +install: pip install . +script: python -m phabricator.tests.test_phabricator +deploy: + provider: pypi + user: disqus + password: + secure: AJ7zSLd6BgI4W8Kp3KEx5O40bUJA91PkgLTZb5MnCx4/8nUPlkk+LqvodaiiJQEGzpP8COPvRlzJ/swd8d0P38+Se6V83wA43MylimzrgngO6t3c/lXa/aMnrRzSpSfK5QznEMP2zcSU1ReD+2dNr7ATKajbGqTzrCFk/hQPMZ0= + on: + tags: true From da99adb84e4a0bac28c3ba9da56081c97fc072b3 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 8 Jul 2016 18:35:24 +0300 Subject: [PATCH 25/44] Remove support for old Python 3.x versions --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80deb19..374e740 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ language: python python: - '2.7' -- '3.3' -- '3.4' - '3.5' install: pip install . script: python -m phabricator.tests.test_phabricator From dac1219c54eaf1be48ea29ceab0ecad6d1032d9a Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 8 Jul 2016 18:38:58 +0300 Subject: [PATCH 26/44] 0.7.0 --- CHANGES | 5 +++++ setup.py | 7 ++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 13f6f3d..5f8d0bf 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +0.7.0 + +* Allow for nested methods to support conduit calls such as diffusion.repository.edit +* Fix regular expressions that cause type parsing to fail + 0.6.1 * Fix Python 3 related issues diff --git a/setup.py b/setup.py index 8e39305..bff54d5 100644 --- a/setup.py +++ b/setup.py @@ -14,8 +14,8 @@ setup( name='phabricator', - version='0.6.1', - author='DISQUS', + version='0.7.0', + author='Disqus', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator', description='Phabricator API Bindings', @@ -31,11 +31,8 @@ 'Topic :: Software Development', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', ], ) From b48bf6fbb22278c77c91fbbb273aeb3095f40d7a Mon Sep 17 00:00:00 2001 From: framawiki Date: Mon, 12 Jun 2017 21:40:14 +0200 Subject: [PATCH 27/44] Readme: Explain that you have to use /api/ host url (#45) --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 4c3d28c..2ce845a 100644 --- a/README.rst +++ b/README.rst @@ -20,6 +20,10 @@ Use the API by instantiating it, and then calling the method through dotted nota phab = Phabricator() # This will use your ~/.arcrc file phab.user.whoami() +You can also use:: + + phab = Phabricator(host='https://my-phabricator.org/api/', token='api-mytoken') + Parameters are passed as keyword arguments to the resource call:: phab.user.find(aliases=["sugarc0de"]) From a52c0e1357532f9ef8b26321d3728a0edead6ed4 Mon Sep 17 00:00:00 2001 From: Onkur Sen Date: Tue, 25 Jul 2017 14:57:04 -0700 Subject: [PATCH 28/44] Add diffusion.commit.search endpoint to interfaces.json --- phabricator/interfaces.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phabricator/interfaces.json b/phabricator/interfaces.json index 6d268ee..0bfa36a 100644 --- a/phabricator/interfaces.json +++ b/phabricator/interfaces.json @@ -1 +1 @@ -{"almanac.device.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"almanac.service.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"audit.query":{"description":"Query audit requests.","params":{"auditorPHIDs":"optional list\u003cphid\u003e","commitPHIDs":"optional list\u003cphid\u003e","status":"optional string-constant\u003c\"audit-status-any\", \"audit-status-open\", \"audit-status-concern\", \"audit-status-accepted\", \"audit-status-partial\"\u003e (default = \"audit-status-any\")","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"auth.logout":{"description":"Terminate all web login sessions. If called via OAuth, also terminate the current OAuth token.\n\nWARNING: This method does what it claims on the label. If you call this method via the test console in the web UI, it will log you out!","params":[],"return":"void"},"auth.querypublickeys":{"description":"Query public keys.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","objectPHIDs":"optional list\u003cphid\u003e","keys":"optional list\u003cstring\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"result-set"},"badges.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"badges.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"conduit.connect":{"description":"Connect a session-based client.","params":{"client":"required string","clientVersion":"required int","clientDescription":"optional string","user":"optional string","authToken":"optional int","authSignature":"optional string","host":"deprecated"},"return":"dict\u003cstring, any\u003e"},"conduit.getcapabilities":{"description":"List capabilities, wire formats, and authentication protocols available on this server.","params":[],"return":"dict\u003cstring, any\u003e"},"conduit.getcertificate":{"description":"Retrieve certificate information for a user.","params":{"token":"required string","host":"required string"},"return":"dict\u003cstring, any\u003e"},"conduit.ping":{"description":"Basic ping for monitoring or a health-check.","params":[],"return":"string"},"conduit.query":{"description":"Returns the parameters of the Conduit methods.","params":[],"return":"dict\u003cdict\u003e"},"conpherence.createthread":{"description":"Create a new conpherence thread.","params":{"title":"optional string","message":"required string","participantPHIDs":"required list\u003cphids\u003e"},"return":"nonempty dict"},"conpherence.querythread":{"description":"Query for Conpherence threads for the logged in user. You can query by IDs or PHIDs for specific Conpherence threads. Otherwise, specify limit and offset to query the most recently updated Conpherences for the logged in user.","params":{"ids":"optional array\u003cint\u003e","phids":"optional array\u003cphids\u003e","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.querytransaction":{"description":"Query for transactions for the logged in user within a specific Conpherence room. You can specify the room by ID or PHID. Otherwise, specify limit and offset to query the most recent transactions within the Conpherence room for the logged in user.","params":{"roomID":"optional int","roomPHID":"optional phid","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.updatethread":{"description":"Update an existing conpherence room.","params":{"id":"optional int","phid":"optional phid","title":"optional string","message":"optional string","addParticipantPHIDs":"optional list\u003cphids\u003e","removeParticipantPHID":"optional phid"},"return":"bool"},"dashboard.panel.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"differential.close":{"description":"Close a Differential revision.","params":{"revisionID":"required int"},"return":"void"},"differential.createcomment":{"description":"Add a comment to a Differential revision.","params":{"revision_id":"required revisionid","message":"optional string","action":"optional string","silent":"optional bool","attach_inlines":"optional bool"},"return":"nonempty dict"},"differential.creatediff":{"description":"Create a new Differential diff.","params":{"changes":"required list\u003cdict\u003e","sourceMachine":"required string","sourcePath":"required string","branch":"required string","bookmark":"optional string","sourceControlSystem":"required string-constant\u003c\"svn\", \"git\", \"hg\"\u003e","sourceControlPath":"required string","sourceControlBaseRevision":"required string","creationMethod":"optional string","lintStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","unitStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","repositoryPHID":"optional phid","parentRevisionID":"deprecated","authorPHID":"deprecated","repositoryUUID":"deprecated"},"return":"nonempty dict"},"differential.createinline":{"description":"Add an inline comment to a Differential revision.","params":{"revisionID":"optional revisionid","diffID":"optional diffid","filePath":"required string","isNewFile":"required bool","lineNumber":"required int","lineLength":"optional int","content":"required string"},"return":"nonempty dict"},"differential.createrawdiff":{"description":"Create a new Differential diff from a raw diff source.","params":{"diff":"required string","repositoryPHID":"optional string","viewPolicy":"optional string"},"return":"nonempty dict"},"differential.createrevision":{"description":"Create a new Differential revision.","params":{"user":"ignored","diffid":"required diffid","fields":"required dict"},"return":"nonempty dict"},"differential.getcommitmessage":{"description":"Retrieve Differential commit messages or message templates.","params":{"revision_id":"optional revision_id","fields":"optional dict\u003cstring, wild\u003e","edit":"optional string-constant\u003c\"edit\", \"create\"\u003e"},"return":"nonempty string"},"differential.getcommitpaths":{"description":"Query which paths should be included when committing a Differential revision.","params":{"revision_id":"required int"},"return":"nonempty list\u003cstring\u003e"},"differential.getrawdiff":{"description":"Retrieve a raw diff","params":{"diffID":"required diffID"},"return":"nonempty string"},"differential.parsecommitmessage":{"description":"Parse commit messages for Differential fields.","params":{"corpus":"required string","partial":"optional bool"},"return":"nonempty dict"},"differential.query":{"description":"Query Differential revisions which match certain criteria.","params":{"authors":"optional list\u003cphid\u003e","ccs":"optional list\u003cphid\u003e","reviewers":"optional list\u003cphid\u003e","paths":"optional list\u003cpair\u003ccallsign, path\u003e\u003e","commitHashes":"optional list\u003cpair\u003cstring-constant\u003c\"gtcm\", \"gttr\", \"hgcm\"\u003e, string\u003e\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-accepted\", \"status-closed\"\u003e","order":"optional string-constant\u003c\"order-modified\", \"order-created\"\u003e","limit":"optional uint","offset":"optional uint","ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","subscribers":"optional list\u003cphid\u003e","responsibleUsers":"optional list\u003cphid\u003e","branches":"optional list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"differential.querydiffs":{"description":"Query differential diffs which match certain criteria.","params":{"ids":"optional list\u003cuint\u003e","revisionIDs":"optional list\u003cuint\u003e"},"return":"list\u003cdict\u003e"},"differential.setdiffproperty":{"description":"Attach properties to Differential diffs.","params":{"diff_id":"required diff_id","name":"required string","data":"required string"},"return":"void"},"differential.updaterevision":{"description":"Update a Differential revision.","params":{"id":"required revisionid","diffid":"required diffid","fields":"required dict","message":"required string"},"return":"nonempty dict"},"differential.revision.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"differential.find":{"description":"Query Differential revisions which match certain criteria.","params":{"query":"required string-constant\u003c\"open\", \"committable\", \"revision-ids\", \"phids\"\u003e","guids":"required nonempty list\u003cguids\u003e"},"return":"nonempty list\u003cdict\u003e"},"differential.getalldiffs":{"description":"Load all diffs for given revisions from Differential.","params":{"revision_ids":"required list\u003cint\u003e"},"return":"dict"},"differential.getdiff":{"description":"Load the content of a diff from Differential by revision ID or diff ID.","params":{"revision_id":"optional id","diff_id":"optional id"},"return":"nonempty dict"},"differential.getrevision":{"description":"Load the content of a revision from Differential.","params":{"revision_id":"required id"},"return":"nonempty dict"},"differential.getrevisioncomments":{"description":"Retrieve Differential Revision Comments.","params":{"ids":"required list\u003cint\u003e","inlines":"optional bool (deprecated)"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"diffusion.findsymbols":{"description":"Retrieve Diffusion symbol information.","params":{"name":"optional string","namePrefix":"optional string","context":"optional string","language":"optional string","type":"optional string","repositoryPHID":"optional string"},"return":"nonempty list\u003cdict\u003e"},"diffusion.getrecentcommitsbypath":{"description":"Get commit identifiers for recent commits affecting a given path.","params":{"callsign":"required string","path":"required string","branch":"optional string","limit":"optional int"},"return":"nonempty list\u003cstring\u003e"},"diffusion.querycommits":{"description":"Retrieve information about commits.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cstring\u003e","repositoryPHID":"optional phid","needMessages":"optional bool","bypassCache":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, dict\u003e"},"diffusion.blame":{"description":"Get blame information for a list of paths.","params":{"paths":"required list\u003cstring\u003e","commit":"required string","timeout":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"map\u003cstring, wild\u003e"},"diffusion.branchquery":{"description":"Determine what branches exist for a repository.","params":{"closed":"optional bool","limit":"optional int","offset":"optional int","contains":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cdict\u003e"},"diffusion.browsequery":{"description":"File(s) information for a repository at an (optional) path and (optional) commit.","params":{"path":"optional string","commit":"optional string","needValidityOnly":"optional bool","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.commitparentsquery":{"description":"Get the commit identifiers for a commit's parent or parents.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.diffquery":{"description":"Get diff information from a repository for a specific path at an (optional) commit.","params":{"path":"required string","commit":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.existsquery":{"description":"Determine if code exists in a version control system.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"bool"},"diffusion.filecontentquery":{"description":"Retrieve file content from a repository.","params":{"path":"required string","commit":"required string","timeout":"optional int","byteLimit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.getlintmessages":{"description":"Get lint messages for existing code.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"optional string","files":"required list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"diffusion.historyquery":{"description":"Returns history information for a repository at a specific commit and path.","params":{"commit":"required string","path":"required string","offset":"required int","limit":"required int","needDirectChanges":"optional bool","needChildChanges":"optional bool","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.internal.gitrawdiffquery":{"description":"Internal method for getting raw diff information.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"string"},"diffusion.lastmodifiedquery":{"description":"Get the commits at which paths were last modified.","params":{"paths":"required map\u003cstring, string\u003e","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"map\u003cstring, string\u003e"},"diffusion.looksoon":{"description":"Advises Phabricator to look for new commits in a repository as soon as possible. This advice is most useful if you have just pushed new commits to that repository.","params":{"callsigns":"optional list\u003cstring\u003e (deprecated)","repositories":"optional list\u003cstring\u003e","urgency":"optional string"},"return":"void"},"diffusion.mergedcommitsquery":{"description":"Merged commit information for a specific commit in a repository.","params":{"commit":"required string","limit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.querypaths":{"description":"Filename search on a repository.","params":{"path":"required string","commit":"required string","pattern":"optional string","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.rawdiffquery":{"description":"Get raw diff information from a repository for a specific commit at an (optional) path.","params":{"commit":"required string","path":"optional string","timeout":"optional int","byteLimit":"optional int","linesOfContext":"optional int","againstCommit":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"string"},"diffusion.refsquery":{"description":"Query a git repository for ref information at a specific commit.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.repository.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"diffusion.repository.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"diffusion.resolverefs":{"description":"Resolve references into stable, canonical identifiers.","params":{"refs":"required list\u003cstring\u003e","types":"optional list\u003cstring\u003e","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"dict\u003cstring, list\u003cdict\u003cstring, wild\u003e\u003e\u003e"},"diffusion.searchquery":{"description":"Search (grep) a repository at a specific path and commit.","params":{"path":"required string","commit":"optional string","grep":"required string","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.tagsquery":{"description":"Retrieve information about tags in a repository.","params":{"names":"optional list\u003cstring\u003e","commit":"optional string","needMessages":"optional bool","offset":"optional int","limit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.updatecoverage":{"description":"Publish coverage information for a repository.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"required string","coverage":"required map\u003cstring, string\u003e","mode":"optional string-constant\u003c\"overwrite\", \"update\"\u003e"},"return":"void"},"diffusion.uri.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"diffusion.createcomment":{"description":"Add a comment to a Diffusion commit. By specifying an action of \"concern\", \"accept\", \"resign\", or \"close\", auditing actions can be triggered. Defaults to \"comment\".","params":{"phid":"required string","action":"optional string","message":"required string","silent":"optional bool"},"return":"bool"},"feed.publish":{"description":"Publish a story to the feed.","params":{"type":"required string","data":"required dict","time":"optional int"},"return":"nonempty phid"},"feed.query":{"description":"Query the feed for stories","params":{"filterPHIDs":"optional list \u003cphid\u003e","limit":"optional int (default 100)","after":"optional int","before":"optional int","view":"optional string (data, html, html-summary, text)"},"return":"nonempty dict"},"file.allocate":{"description":"Prepare to upload a file.","params":{"name":"string","contentLength":"int","contentHash":"optional string","viewPolicy":"optional string","deleteAfterEpoch":"optional int"},"return":"map\u003cstring, wild\u003e"},"file.download":{"description":"Download a file from the server.","params":{"phid":"required phid"},"return":"nonempty base64-bytes"},"file.info":{"description":"Get information about a file.","params":{"phid":"optional phid","id":"optional id"},"return":"nonempty dict"},"file.querychunks":{"description":"Get information about file chunks.","params":{"filePHID":"phid"},"return":"list\u003cwild\u003e"},"file.upload":{"description":"Upload a file to the server.","params":{"data_base64":"required nonempty base64-bytes","name":"optional string","viewPolicy":"optional valid policy string or \u003cphid\u003e","canCDN":"optional bool"},"return":"nonempty guid"},"file.uploadchunk":{"description":"Upload a chunk of file data to the server.","params":{"filePHID":"phid","byteStart":"int","data":"string","dataEncoding":"string"},"return":"void"},"file.uploadhash":{"description":"Upload a file to the server using content hash.","params":{"hash":"required nonempty string","name":"required nonempty string"},"return":"phid or null"},"flag.delete":{"description":"Clear a flag.","params":{"id":"optional id","objectPHID":"optional phid"},"return":"dict | null"},"flag.edit":{"description":"Create or modify a flag.","params":{"objectPHID":"required phid","color":"optional int","note":"optional string"},"return":"dict"},"flag.query":{"description":"Query flag markers.","params":{"ownerPHIDs":"optional list\u003cphid\u003e","types":"optional list\u003ctype\u003e","objectPHIDs":"optional list\u003cphid\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"harbormaster.createartifact":{"description":"Use this method to attach artifacts to build targets while running builds. Artifacts can be used to carry data through a complex build workflow, provide extra information to users, or store build results.\n\nWhen creating an artifact, you will choose an `artifactType` from this table. These types of artifacts are supported:\n| Artifact Type | Name | Summary |\n|-------------|--------------|--------------|\n| `host` | **Drydock Host** | References a host lease from Drydock. |\n| `working-copy` | **Drydock Working Copy** | References a working copy lease from Drydock. |\n| `file` | **File** | Stores a reference to file data which has been uploaded to Phabricator. |\n| `uri` | **URI** | Stores a URI. |\n\nEach artifact also needs an `artifactKey`, which names the artifact. Finally, you will provide some `artifactData` to fill in the content of the artifact. The data you provide depends on what type of artifact you are creating.\nDrydock Host\n--------------------------\n\nReferences a host lease from Drydock.\n\nCreate an artifact of this type by passing `host` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nDrydock Working Copy\n--------------------------\n\nReferences a working copy lease from Drydock.\n\nCreate an artifact of this type by passing `working-copy` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nFile\n--------------------------\n\nStores a reference to file data which has been uploaded to Phabricator.\n\nCreate an artifact of this type by passing `file` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `filePHID` | \/\/string\/\/ | File to create an artifact from. |\nFor example:\n```lang=json\n{\n \"filePHID\": \"PHID-FILE-abcdefghijklmnopqrst\"\n}\n\n```\nURI\n--------------------------\n\nStores a URI.\n\nWith `ui.external`, you can use this artifact type to add links to build results in an external build system.\n\nCreate an artifact of this type by passing `uri` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `uri` | \/\/string\/\/ | The URI to store. |\n| `name` | \/\/optional string\/\/ | Optional label for this URI. |\n| `ui.external` | \/\/optional bool\/\/ | If true, display this URI in the UI as an link to additional build details in an external build system. |\nFor example:\n```lang=json\n{\n \"uri\": \"https:\/\/buildserver.mycompany.com\/build\/123\/\",\n \"name\": \"View External Build Results\",\n \"ui.external\": true\n}\n\n```","params":{"buildTargetPHID":"phid","artifactKey":"string","artifactType":"string","artifactData":"map\u003cstring, wild\u003e"},"return":"wild"},"harbormaster.queryautotargets":{"description":"Load or create build autotargets.","params":{"objectPHID":"phid","targetKeys":"list\u003cstring\u003e"},"return":"map\u003cstring, phid\u003e"},"harbormaster.querybuildables":{"description":"Query Harbormaster buildables.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildablePHIDs":"optional list\u003cphid\u003e","containerPHIDs":"optional list\u003cphid\u003e","manualBuildables":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.querybuilds":{"description":"Query Harbormaster builds.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildStatuses":"optional list\u003cstring\u003e","buildablePHIDs":"optional list\u003cphid\u003e","buildPlanPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.sendmessage":{"description":"Send a message about the status of a build target to Harbormaster, notifying the application of build results in an external system.\n\nSending Messages\n================\nIf you run external builds, you can use this method to publish build results back into Harbormaster after the external system finishes work or as it makes progress.\n\nThe simplest way to use this method is to call it once after the build finishes with a `pass` or `fail` message. This will record the build result, and continue the next step in the build if the build was waiting for a result.\n\nWhen you send a status message about a build target, you can optionally include detailed `lint` or `unit` results alongside the message. See below for details.\n\nIf you want to report intermediate results but a build hasn't completed yet, you can use the `work` message. This message doesn't have any direct effects, but allows you to send additional data to update the progress of the build target. The target will continue waiting for a completion message, but the UI will update to show the progress which has been made.\n\nMessage Types\n=============\nWhen you send Harbormaster a message, you must include a `type`, which describes the overall state of the build. For example, use `pass` to tell Harbomaster that a build completed successfully.\n\nSupported message types are:\n\n| Type | Description |\n|--------------|--------------|\n| `pass` | Report that the target is complete, and the target has passed. |\n| `fail` | Report that the target is complete, and the target has failed. |\n| `work` | Report that work on the target is ongoing. This message can be used to report partial results during a build. |\n\nUnit Results\n============\nYou can report test results alongside a message. The simplest way to do this is to report all the results alongside a `pass` or `fail` message, but you can also send a `work` message to report intermediate results.\n\nTo provide unit test results, pass a list of results in the `unit` parameter. Each result shoud be a dictionary with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short test name, like \"ExampleTest\". |\n| `result` | \/\/string\/\/ | Result of the test. |\n| `namespace` | \/\/optional string\/\/ | Optional namespace for this test. This is organizational and is often a class or module name, like \"ExampleTestCase\". |\n| `engine` | \/\/optional string\/\/ | Test engine running the test, like \"JavascriptTestEngine\". This primarily prevents collisions between tests with the same name in different test suites (for example, a Javascript test and a Python test). |\n| `duration` | \/\/optional float or int\/\/ | Runtime duration of the test, in seconds. |\n| `path` | \/\/optional string\/\/ | Path to the file where the test is declared, relative to the project root. |\n| `coverage` | \/\/optional map\u003cstring, wild\u003e\/\/ | Coverage information for this test. |\n| `details` | \/\/optional string\/\/ | Additional human-readable information about the failure. |\n\nThe `result` parameter recognizes these test results:\n\n| Key | Name | Description |\n|-------------|--------------|--------------|\n| `pass` | **Pass** | The test passed. |\n| `fail` | **Fail** | The test failed. |\n| `skip` | **Skip** | The test was not executed. |\n| `broken` | **Broken** | The test failed in an abnormal or severe way. For example, the harness crashed instead of reporting a failure. |\n| `unsound` | **Unsound** | The test failed, but this change is probably not what broke it. For example, it might have already been failing. |\n\nThis is a simple, valid value for the `unit` parameter. It reports one passing test and one failing test:\n\n\n\n```lang=json\n[\n {\n \"name\": \"PassingTest\",\n \"result\": \"pass\"\n },\n {\n \"name\": \"FailingTest\",\n \"result\": \"fail\"\n }\n]\n```\n\nLint Results\n============\nLike unit test results, you can report lint results alongside a message. The `lint` parameter should contain results as a list of dictionaries with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short message name, like \"Syntax Error\". |\n| `code` | \/\/string\/\/ | Lint message code identifying the type of message, like \"ERR123\". |\n| `severity` | \/\/string\/\/ | Severity of the message. |\n| `path` | \/\/string\/\/ | Path to the file containing the lint message, from the project root. |\n| `line` | \/\/optional int\/\/ | Line number in the file where the text which triggered the message first appears. The first line of the file is line 1, not line 0. |\n| `char` | \/\/optional int\/\/ | Byte position on the line where the text which triggered the message starts. The first byte on the line is byte 1, not byte 0. This position is byte-based (not character-based) because not all lintable files have a valid character encoding. |\n| `description` | \/\/optional string\/\/ | Long explanation of the lint message. |\n\nThe `severity` parameter recognizes these severity levels:\n\n| Key | Name |\n|-------------|--------------|\n| `advice` | **Advice** |\n| `autofix` | **Auto-Fix** |\n| `warning` | **Warning** |\n| `error` | **Error** |\n| `disabled` | **Disabled** |\n\nThis is a simple, valid value for the `lint` parameter. It reports one error and one warning:\n\n```lang=json\n[\n {\n \"name\": \"Syntax Error\",\n \"code\": \"EXAMPLE1\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/example.c\",\n \"line\": 17,\n \"char\": 3\n },\n {\n \"name\": \"Not A Haiku\",\n \"code\": \"EXAMPLE2\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/source.cpp\",\n \"line\": 23,\n \"char\": 1,\n \"description\": \"This function definition is not a haiku.\"\n }\n]\n```\n\n","params":{"buildTargetPHID":"required phid","type":"required string-constant\u003c\"pass\", \"fail\", \"work\"\u003e","unit":"optional list\u003cwild\u003e","lint":"optional list\u003cwild\u003e"},"return":"void"},"macro.query":{"description":"Retrieve image macro information.","params":{"authorPHIDs":"optional list\u003cphid\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cid\u003e","names":"optional list\u003cstring\u003e","nameLike":"optional string"},"return":"list\u003cdict\u003e"},"macro.creatememe":{"description":"Generate a meme.","params":{"macroName":"string","upperText":"optional string","lowerText":"optional string"},"return":"string"},"maniphest.createtask":{"description":"Create a new Maniphest task.","params":{"title":"required string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict"},"return":"nonempty dict"},"maniphest.gettasktransactions":{"description":"Retrieve Maniphest task transactions.","params":{"ids":"required list\u003cint\u003e"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"maniphest.info":{"description":"Retrieve information about a Maniphest task, given its ID.","params":{"task_id":"required id"},"return":"nonempty dict"},"maniphest.query":{"description":"Execute complex searches for Maniphest tasks.","params":{"ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","ownerPHIDs":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","projectPHIDs":"optional list\u003cphid\u003e","ccPHIDs":"optional list\u003cphid\u003e","fullText":"optional string","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-resolved\", \"status-wontfix\", \"status-invalid\", \"status-spite\", \"status-duplicate\"\u003e","order":"optional string-constant\u003c\"order-priority\", \"order-created\", \"order-modified\"\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"maniphest.querystatuses":{"description":"Retrieve information about possible Maniphest task status values.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"maniphest.update":{"description":"Update an existing Maniphest task.","params":{"id":"optional int","phid":"optional int","title":"optional string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict","status":"optional string","comments":"optional string"},"return":"nonempty dict"},"maniphest.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"maniphest.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"owners.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"owners.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"owners.query":{"description":"Query for Owners packages. Obsoleted by \"owners.search\".","params":{"userOwner":"optional string","projectOwner":"optional string","userAffiliated":"optional string","repositoryCallsign":"optional string","path":"optional string"},"return":"dict\u003cphid -\u003e dict of package info\u003e"},"passphrase.query":{"description":"Query credentials.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","needSecrets":"optional bool","needPublicKeys":"optional bool","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"paste.create":{"description":"Create a new paste.","params":{"content":"required string","title":"optional string","language":"optional string"},"return":"nonempty dict"},"paste.query":{"description":"Query Pastes.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","after":"optional int","limit":"optional int, default = 100"},"return":"list\u003cdict\u003e"},"paste.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"paste.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"paste.info":{"description":"Retrieve an array of information about a paste.","params":{"paste_id":"required id"},"return":"nonempty dict"},"phame.blog.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"phame.blog.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"phame.post.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"phame.post.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"phid.lookup":{"description":"Look up objects by name.","params":{"names":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.query":{"description":"Retrieve information about arbitrary PHIDs.","params":{"phids":"required list\u003cphid\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.info":{"description":"Retrieve information about an arbitrary PHID.","params":{"phid":"required phid"},"return":"nonempty dict\u003cstring, wild\u003e"},"phragment.getpatch":{"description":"Retrieve the patches to apply for a given set of files.","params":{"path":"required string","state":"required dict\u003cstring, string\u003e"},"return":"nonempty dict"},"phragment.queryfragments":{"description":"Query fragments based on their paths.","params":{"paths":"required list\u003cstring\u003e"},"return":"nonempty dict"},"phriction.create":{"description":"Create a Phriction document.","params":{"slug":"required string","title":"required string","content":"required string","description":"optional string"},"return":"nonempty dict"},"phriction.edit":{"description":"Update a Phriction document.","params":{"slug":"required string","title":"optional string","content":"optional string","description":"optional string"},"return":"nonempty dict"},"phriction.history":{"description":"Retrieve history about a Phriction document.","params":{"slug":"required string"},"return":"nonempty list"},"phriction.info":{"description":"Retrieve information about a Phriction document.","params":{"slug":"required string"},"return":"nonempty dict"},"project.create":{"description":"Create a project.","params":{"name":"required string","members":"optional list\u003cphid\u003e","icon":"optional string","color":"optional string","tags":"optional list\u003cstring\u003e"},"return":"dict"},"project.query":{"description":"Execute searches for Projects.","params":{"ids":"optional list\u003cint\u003e","names":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","slugs":"optional list\u003cstring\u003e","icons":"optional list\u003cstring\u003e","colors":"optional list\u003cstring\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-active\", \"status-archived\"\u003e","members":"optional list\u003cphid\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"project.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"project.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"releeph.getbranches":{"description":"Return information about all active Releeph branches.","params":[],"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"releeph.querybranches":{"description":"Query information about Releeph branches.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","productPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryproducts":{"description":"Query information about Releeph products.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","repositoryPHIDs":"optional list\u003cphid\u003e","isActive":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryrequests":{"description":"Return information about all Releeph requests linked to the given ids.","params":{"revisionPHIDs":"optional list\u003cphid\u003e","requestedCommitPHIDs":"optional list\u003cphid\u003e"},"return":"dict\u003cstring, wild\u003e"},"releeph.request":{"description":"Request a commit or diff to be picked to a branch.","params":{"branchPHID":"required string","things":"required list\u003cstring\u003e","fields":"dict\u003cstring, string\u003e"},"return":"dict\u003cstring, wild\u003e"},"releephwork.canpush":{"description":"Return whether the conduit user is allowed to push.","params":{"projectPHID":"required string"},"return":"bool"},"releephwork.getauthorinfo":{"description":"Return a string to use as the VCS author.","params":{"userPHID":"required string","vcsType":"required string"},"return":"nonempty string"},"releephwork.getbranch":{"description":"Return information to help checkout \/ cut a Releeph branch.","params":{"branchPHID":"required string"},"return":"dict\u003cstring, wild\u003e"},"releephwork.getbranchcommitmessage":{"description":"Get a commit message for committing a Releeph branch.","params":{"branchPHID":"required string"},"return":"nonempty string"},"releephwork.getcommitmessage":{"description":"Get commit message components for building a ReleephRequest commit message.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e"},"return":"dict\u003cstring, string\u003e"},"releephwork.nextrequest":{"description":"Return info required to cut a branch, and pick and revert ReleephRequests.","params":{"branchPHID":"required phid","seen":"required map\u003cstring, bool\u003e"},"return":""},"releephwork.record":{"description":"Record whether we committed a pick or revert to the upstream repository.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","commitIdentifier":"required string"},"return":"void"},"releephwork.recordpickstatus":{"description":"Record whether a pick or revert was successful or not.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","ok":"required bool","dryRun":"optional bool","details":"optional dict\u003cstring, wild\u003e"},"return":""},"remarkup.process":{"description":"Process text through remarkup in Phabricator context.","params":{"context":"required string-constant\u003c\"phriction\", \"maniphest\", \"differential\", \"phame\", \"feed\", \"diffusion\"\u003e","contents":"required list\u003cstring\u003e"},"return":"nonempty dict"},"repository.query":{"description":"Query repositories.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","callsigns":"optional list\u003cstring\u003e","vcsTypes":"optional list\u003cstring\u003e","remoteURIs":"optional list\u003cstring\u003e","uuids":"optional list\u003cstring\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"slowvote.info":{"description":"Retrieve an array of information about a poll.","params":{"poll_id":"required id"},"return":"nonempty dict"},"token.give":{"description":"Give or change a token.","params":{"tokenPHID":"phid|null","objectPHID":"phid"},"return":"void"},"token.given":{"description":"Query tokens given to objects.","params":{"authorPHIDs":"list\u003cphid\u003e","objectPHIDs":"list\u003cphid\u003e","tokenPHIDs":"list\u003cphid\u003e"},"return":"list\u003cdict\u003e"},"token.query":{"description":"Query tokens.","params":[],"return":"list\u003cdict\u003e"},"user.disable":{"description":"Permanently disable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.enable":{"description":"Re-enable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.query":{"description":"Query users.","params":{"usernames":"optional list\u003cstring\u003e","emails":"optional list\u003cstring\u003e","realnames":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cuint\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"user.whoami":{"description":"Retrieve information about the logged-in user.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"user.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"user.find":{"description":"Lookup PHIDs by username. Obsoleted by \"user.query\".","params":{"aliases":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, phid\u003e"}} \ No newline at end of file +{"almanac.device.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"almanac.service.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"audit.query":{"description":"Query audit requests.","params":{"auditorPHIDs":"optional list\u003cphid\u003e","commitPHIDs":"optional list\u003cphid\u003e","status":"optional string-constant\u003c\"audit-status-any\", \"audit-status-open\", \"audit-status-concern\", \"audit-status-accepted\", \"audit-status-partial\"\u003e (default = \"audit-status-any\")","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"auth.logout":{"description":"Terminate all web login sessions. If called via OAuth, also terminate the current OAuth token.\n\nWARNING: This method does what it claims on the label. If you call this method via the test console in the web UI, it will log you out!","params":[],"return":"void"},"auth.querypublickeys":{"description":"Query public keys.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","objectPHIDs":"optional list\u003cphid\u003e","keys":"optional list\u003cstring\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"result-set"},"badges.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"badges.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"conduit.connect":{"description":"Connect a session-based client.","params":{"client":"required string","clientVersion":"required int","clientDescription":"optional string","user":"optional string","authToken":"optional int","authSignature":"optional string","host":"deprecated"},"return":"dict\u003cstring, any\u003e"},"conduit.getcapabilities":{"description":"List capabilities, wire formats, and authentication protocols available on this server.","params":[],"return":"dict\u003cstring, any\u003e"},"conduit.getcertificate":{"description":"Retrieve certificate information for a user.","params":{"token":"required string","host":"required string"},"return":"dict\u003cstring, any\u003e"},"conduit.ping":{"description":"Basic ping for monitoring or a health-check.","params":[],"return":"string"},"conduit.query":{"description":"Returns the parameters of the Conduit methods.","params":[],"return":"dict\u003cdict\u003e"},"conpherence.createthread":{"description":"Create a new conpherence thread.","params":{"title":"optional string","message":"required string","participantPHIDs":"required list\u003cphids\u003e"},"return":"nonempty dict"},"conpherence.querythread":{"description":"Query for Conpherence threads for the logged in user. You can query by IDs or PHIDs for specific Conpherence threads. Otherwise, specify limit and offset to query the most recently updated Conpherences for the logged in user.","params":{"ids":"optional array\u003cint\u003e","phids":"optional array\u003cphids\u003e","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.querytransaction":{"description":"Query for transactions for the logged in user within a specific Conpherence room. You can specify the room by ID or PHID. Otherwise, specify limit and offset to query the most recent transactions within the Conpherence room for the logged in user.","params":{"roomID":"optional int","roomPHID":"optional phid","limit":"optional int","offset":"optional int"},"return":"nonempty dict"},"conpherence.updatethread":{"description":"Update an existing conpherence room.","params":{"id":"optional int","phid":"optional phid","title":"optional string","message":"optional string","addParticipantPHIDs":"optional list\u003cphids\u003e","removeParticipantPHID":"optional phid"},"return":"bool"},"dashboard.panel.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"differential.close":{"description":"Close a Differential revision.","params":{"revisionID":"required int"},"return":"void"},"differential.createcomment":{"description":"Add a comment to a Differential revision.","params":{"revision_id":"required revisionid","message":"optional string","action":"optional string","silent":"optional bool","attach_inlines":"optional bool"},"return":"nonempty dict"},"differential.creatediff":{"description":"Create a new Differential diff.","params":{"changes":"required list\u003cdict\u003e","sourceMachine":"required string","sourcePath":"required string","branch":"required string","bookmark":"optional string","sourceControlSystem":"required string-constant\u003c\"svn\", \"git\", \"hg\"\u003e","sourceControlPath":"required string","sourceControlBaseRevision":"required string","creationMethod":"optional string","lintStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","unitStatus":"required string-constant\u003c\"none\", \"skip\", \"okay\", \"warn\", \"fail\"\u003e","repositoryPHID":"optional phid","parentRevisionID":"deprecated","authorPHID":"deprecated","repositoryUUID":"deprecated"},"return":"nonempty dict"},"differential.createinline":{"description":"Add an inline comment to a Differential revision.","params":{"revisionID":"optional revisionid","diffID":"optional diffid","filePath":"required string","isNewFile":"required bool","lineNumber":"required int","lineLength":"optional int","content":"required string"},"return":"nonempty dict"},"differential.createrawdiff":{"description":"Create a new Differential diff from a raw diff source.","params":{"diff":"required string","repositoryPHID":"optional string","viewPolicy":"optional string"},"return":"nonempty dict"},"differential.createrevision":{"description":"Create a new Differential revision.","params":{"user":"ignored","diffid":"required diffid","fields":"required dict"},"return":"nonempty dict"},"differential.getcommitmessage":{"description":"Retrieve Differential commit messages or message templates.","params":{"revision_id":"optional revision_id","fields":"optional dict\u003cstring, wild\u003e","edit":"optional string-constant\u003c\"edit\", \"create\"\u003e"},"return":"nonempty string"},"differential.getcommitpaths":{"description":"Query which paths should be included when committing a Differential revision.","params":{"revision_id":"required int"},"return":"nonempty list\u003cstring\u003e"},"differential.getrawdiff":{"description":"Retrieve a raw diff","params":{"diffID":"required diffID"},"return":"nonempty string"},"differential.parsecommitmessage":{"description":"Parse commit messages for Differential fields.","params":{"corpus":"required string","partial":"optional bool"},"return":"nonempty dict"},"differential.query":{"description":"Query Differential revisions which match certain criteria.","params":{"authors":"optional list\u003cphid\u003e","ccs":"optional list\u003cphid\u003e","reviewers":"optional list\u003cphid\u003e","paths":"optional list\u003cpair\u003ccallsign, path\u003e\u003e","commitHashes":"optional list\u003cpair\u003cstring-constant\u003c\"gtcm\", \"gttr\", \"hgcm\"\u003e, string\u003e\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-accepted\", \"status-closed\"\u003e","order":"optional string-constant\u003c\"order-modified\", \"order-created\"\u003e","limit":"optional uint","offset":"optional uint","ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","subscribers":"optional list\u003cphid\u003e","responsibleUsers":"optional list\u003cphid\u003e","branches":"optional list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"differential.querydiffs":{"description":"Query differential diffs which match certain criteria.","params":{"ids":"optional list\u003cuint\u003e","revisionIDs":"optional list\u003cuint\u003e"},"return":"list\u003cdict\u003e"},"differential.setdiffproperty":{"description":"Attach properties to Differential diffs.","params":{"diff_id":"required diff_id","name":"required string","data":"required string"},"return":"void"},"differential.updaterevision":{"description":"Update a Differential revision.","params":{"id":"required revisionid","diffid":"required diffid","fields":"required dict","message":"required string"},"return":"nonempty dict"},"differential.revision.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"differential.find":{"description":"Query Differential revisions which match certain criteria.","params":{"query":"required string-constant\u003c\"open\", \"committable\", \"revision-ids\", \"phids\"\u003e","guids":"required nonempty list\u003cguids\u003e"},"return":"nonempty list\u003cdict\u003e"},"differential.getalldiffs":{"description":"Load all diffs for given revisions from Differential.","params":{"revision_ids":"required list\u003cint\u003e"},"return":"dict"},"differential.getdiff":{"description":"Load the content of a diff from Differential by revision ID or diff ID.","params":{"revision_id":"optional id","diff_id":"optional id"},"return":"nonempty dict"},"differential.getrevision":{"description":"Load the content of a revision from Differential.","params":{"revision_id":"required id"},"return":"nonempty dict"},"differential.getrevisioncomments":{"description":"Retrieve Differential Revision Comments.","params":{"ids":"required list\u003cint\u003e","inlines":"optional bool (deprecated)"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"diffusion.commit.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https://secure.phabricator.com/diviner/find/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"after":"optional string","attachments":"optional map","before":"optional string","constraints":"optional map","limit":"optional int (default = 100)","order":"optional order","queryKey":"optional string"},"return":"list"},"diffusion.findsymbols":{"description":"Retrieve Diffusion symbol information.","params":{"name":"optional string","namePrefix":"optional string","context":"optional string","language":"optional string","type":"optional string","repositoryPHID":"optional string"},"return":"nonempty list\u003cdict\u003e"},"diffusion.getrecentcommitsbypath":{"description":"Get commit identifiers for recent commits affecting a given path.","params":{"callsign":"required string","path":"required string","branch":"optional string","limit":"optional int"},"return":"nonempty list\u003cstring\u003e"},"diffusion.querycommits":{"description":"Retrieve information about commits.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","names":"optional list\u003cstring\u003e","repositoryPHID":"optional phid","needMessages":"optional bool","bypassCache":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, dict\u003e"},"diffusion.blame":{"description":"Get blame information for a list of paths.","params":{"paths":"required list\u003cstring\u003e","commit":"required string","timeout":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"map\u003cstring, wild\u003e"},"diffusion.branchquery":{"description":"Determine what branches exist for a repository.","params":{"closed":"optional bool","limit":"optional int","offset":"optional int","contains":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cdict\u003e"},"diffusion.browsequery":{"description":"File(s) information for a repository at an (optional) path and (optional) commit.","params":{"path":"optional string","commit":"optional string","needValidityOnly":"optional bool","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.commitparentsquery":{"description":"Get the commit identifiers for a commit's parent or parents.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.diffquery":{"description":"Get diff information from a repository for a specific path at an (optional) commit.","params":{"path":"required string","commit":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.existsquery":{"description":"Determine if code exists in a version control system.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"bool"},"diffusion.filecontentquery":{"description":"Retrieve file content from a repository.","params":{"path":"required string","commit":"required string","timeout":"optional int","byteLimit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.getlintmessages":{"description":"Get lint messages for existing code.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"optional string","files":"required list\u003cstring\u003e"},"return":"list\u003cdict\u003e"},"diffusion.historyquery":{"description":"Returns history information for a repository at a specific commit and path.","params":{"commit":"required string","path":"required string","offset":"required int","limit":"required int","needDirectChanges":"optional bool","needChildChanges":"optional bool","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.internal.gitrawdiffquery":{"description":"Internal method for getting raw diff information.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"string"},"diffusion.lastmodifiedquery":{"description":"Get the commits at which paths were last modified.","params":{"paths":"required map\u003cstring, string\u003e","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"map\u003cstring, string\u003e"},"diffusion.looksoon":{"description":"Advises Phabricator to look for new commits in a repository as soon as possible. This advice is most useful if you have just pushed new commits to that repository.","params":{"callsigns":"optional list\u003cstring\u003e (deprecated)","repositories":"optional list\u003cstring\u003e","urgency":"optional string"},"return":"void"},"diffusion.mergedcommitsquery":{"description":"Merged commit information for a specific commit in a repository.","params":{"commit":"required string","limit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.querypaths":{"description":"Filename search on a repository.","params":{"path":"required string","commit":"required string","pattern":"optional string","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"list\u003cstring\u003e"},"diffusion.rawdiffquery":{"description":"Get raw diff information from a repository for a specific commit at an (optional) path.","params":{"commit":"required string","path":"optional string","timeout":"optional int","byteLimit":"optional int","linesOfContext":"optional int","againstCommit":"optional string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"string"},"diffusion.refsquery":{"description":"Query a git repository for ref information at a specific commit.","params":{"commit":"required string","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.repository.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"diffusion.repository.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"diffusion.resolverefs":{"description":"Resolve references into stable, canonical identifiers.","params":{"refs":"required list\u003cstring\u003e","types":"optional list\u003cstring\u003e","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"dict\u003cstring, list\u003cdict\u003cstring, wild\u003e\u003e\u003e"},"diffusion.searchquery":{"description":"Search (grep) a repository at a specific path and commit.","params":{"path":"required string","commit":"optional string","grep":"required string","limit":"optional int","offset":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.tagsquery":{"description":"Retrieve information about tags in a repository.","params":{"names":"optional list\u003cstring\u003e","commit":"optional string","needMessages":"optional bool","offset":"optional int","limit":"optional int","callsign":"optional string (deprecated)","repository":"optional string","branch":"optional string"},"return":"array"},"diffusion.updatecoverage":{"description":"Publish coverage information for a repository.","params":{"repositoryPHID":"required phid","branch":"required string","commit":"required string","coverage":"required map\u003cstring, string\u003e","mode":"optional string-constant\u003c\"overwrite\", \"update\"\u003e"},"return":"void"},"diffusion.uri.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"diffusion.createcomment":{"description":"Add a comment to a Diffusion commit. By specifying an action of \"concern\", \"accept\", \"resign\", or \"close\", auditing actions can be triggered. Defaults to \"comment\".","params":{"phid":"required string","action":"optional string","message":"required string","silent":"optional bool"},"return":"bool"},"feed.publish":{"description":"Publish a story to the feed.","params":{"type":"required string","data":"required dict","time":"optional int"},"return":"nonempty phid"},"feed.query":{"description":"Query the feed for stories","params":{"filterPHIDs":"optional list \u003cphid\u003e","limit":"optional int (default 100)","after":"optional int","before":"optional int","view":"optional string (data, html, html-summary, text)"},"return":"nonempty dict"},"file.allocate":{"description":"Prepare to upload a file.","params":{"name":"string","contentLength":"int","contentHash":"optional string","viewPolicy":"optional string","deleteAfterEpoch":"optional int"},"return":"map\u003cstring, wild\u003e"},"file.download":{"description":"Download a file from the server.","params":{"phid":"required phid"},"return":"nonempty base64-bytes"},"file.info":{"description":"Get information about a file.","params":{"phid":"optional phid","id":"optional id"},"return":"nonempty dict"},"file.querychunks":{"description":"Get information about file chunks.","params":{"filePHID":"phid"},"return":"list\u003cwild\u003e"},"file.upload":{"description":"Upload a file to the server.","params":{"data_base64":"required nonempty base64-bytes","name":"optional string","viewPolicy":"optional valid policy string or \u003cphid\u003e","canCDN":"optional bool"},"return":"nonempty guid"},"file.uploadchunk":{"description":"Upload a chunk of file data to the server.","params":{"filePHID":"phid","byteStart":"int","data":"string","dataEncoding":"string"},"return":"void"},"file.uploadhash":{"description":"Upload a file to the server using content hash.","params":{"hash":"required nonempty string","name":"required nonempty string"},"return":"phid or null"},"flag.delete":{"description":"Clear a flag.","params":{"id":"optional id","objectPHID":"optional phid"},"return":"dict | null"},"flag.edit":{"description":"Create or modify a flag.","params":{"objectPHID":"required phid","color":"optional int","note":"optional string"},"return":"dict"},"flag.query":{"description":"Query flag markers.","params":{"ownerPHIDs":"optional list\u003cphid\u003e","types":"optional list\u003ctype\u003e","objectPHIDs":"optional list\u003cphid\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"harbormaster.createartifact":{"description":"Use this method to attach artifacts to build targets while running builds. Artifacts can be used to carry data through a complex build workflow, provide extra information to users, or store build results.\n\nWhen creating an artifact, you will choose an `artifactType` from this table. These types of artifacts are supported:\n| Artifact Type | Name | Summary |\n|-------------|--------------|--------------|\n| `host` | **Drydock Host** | References a host lease from Drydock. |\n| `working-copy` | **Drydock Working Copy** | References a working copy lease from Drydock. |\n| `file` | **File** | Stores a reference to file data which has been uploaded to Phabricator. |\n| `uri` | **URI** | Stores a URI. |\n\nEach artifact also needs an `artifactKey`, which names the artifact. Finally, you will provide some `artifactData` to fill in the content of the artifact. The data you provide depends on what type of artifact you are creating.\nDrydock Host\n--------------------------\n\nReferences a host lease from Drydock.\n\nCreate an artifact of this type by passing `host` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nDrydock Working Copy\n--------------------------\n\nReferences a working copy lease from Drydock.\n\nCreate an artifact of this type by passing `working-copy` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `drydockLeasePHID` | \/\/string\/\/ | Drydock working copy lease to create an artifact from. |\nFor example:\n```lang=json\n{\n \"drydockLeasePHID\": \"PHID-DRYL-abcdefghijklmnopqrst\"\n}\n\n```\nFile\n--------------------------\n\nStores a reference to file data which has been uploaded to Phabricator.\n\nCreate an artifact of this type by passing `file` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `filePHID` | \/\/string\/\/ | File to create an artifact from. |\nFor example:\n```lang=json\n{\n \"filePHID\": \"PHID-FILE-abcdefghijklmnopqrst\"\n}\n\n```\nURI\n--------------------------\n\nStores a URI.\n\nWith `ui.external`, you can use this artifact type to add links to build results in an external build system.\n\nCreate an artifact of this type by passing `uri` as the `artifactType`. When creating an artifact of this type, provide these parameters as a dictionary to `artifactData`:\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `uri` | \/\/string\/\/ | The URI to store. |\n| `name` | \/\/optional string\/\/ | Optional label for this URI. |\n| `ui.external` | \/\/optional bool\/\/ | If true, display this URI in the UI as an link to additional build details in an external build system. |\nFor example:\n```lang=json\n{\n \"uri\": \"https:\/\/buildserver.mycompany.com\/build\/123\/\",\n \"name\": \"View External Build Results\",\n \"ui.external\": true\n}\n\n```","params":{"buildTargetPHID":"phid","artifactKey":"string","artifactType":"string","artifactData":"map\u003cstring, wild\u003e"},"return":"wild"},"harbormaster.queryautotargets":{"description":"Load or create build autotargets.","params":{"objectPHID":"phid","targetKeys":"list\u003cstring\u003e"},"return":"map\u003cstring, phid\u003e"},"harbormaster.querybuildables":{"description":"Query Harbormaster buildables.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildablePHIDs":"optional list\u003cphid\u003e","containerPHIDs":"optional list\u003cphid\u003e","manualBuildables":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.querybuilds":{"description":"Query Harbormaster builds.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","buildStatuses":"optional list\u003cstring\u003e","buildablePHIDs":"optional list\u003cphid\u003e","buildPlanPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"wild"},"harbormaster.sendmessage":{"description":"Send a message about the status of a build target to Harbormaster, notifying the application of build results in an external system.\n\nSending Messages\n================\nIf you run external builds, you can use this method to publish build results back into Harbormaster after the external system finishes work or as it makes progress.\n\nThe simplest way to use this method is to call it once after the build finishes with a `pass` or `fail` message. This will record the build result, and continue the next step in the build if the build was waiting for a result.\n\nWhen you send a status message about a build target, you can optionally include detailed `lint` or `unit` results alongside the message. See below for details.\n\nIf you want to report intermediate results but a build hasn't completed yet, you can use the `work` message. This message doesn't have any direct effects, but allows you to send additional data to update the progress of the build target. The target will continue waiting for a completion message, but the UI will update to show the progress which has been made.\n\nMessage Types\n=============\nWhen you send Harbormaster a message, you must include a `type`, which describes the overall state of the build. For example, use `pass` to tell Harbomaster that a build completed successfully.\n\nSupported message types are:\n\n| Type | Description |\n|--------------|--------------|\n| `pass` | Report that the target is complete, and the target has passed. |\n| `fail` | Report that the target is complete, and the target has failed. |\n| `work` | Report that work on the target is ongoing. This message can be used to report partial results during a build. |\n\nUnit Results\n============\nYou can report test results alongside a message. The simplest way to do this is to report all the results alongside a `pass` or `fail` message, but you can also send a `work` message to report intermediate results.\n\nTo provide unit test results, pass a list of results in the `unit` parameter. Each result shoud be a dictionary with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short test name, like \"ExampleTest\". |\n| `result` | \/\/string\/\/ | Result of the test. |\n| `namespace` | \/\/optional string\/\/ | Optional namespace for this test. This is organizational and is often a class or module name, like \"ExampleTestCase\". |\n| `engine` | \/\/optional string\/\/ | Test engine running the test, like \"JavascriptTestEngine\". This primarily prevents collisions between tests with the same name in different test suites (for example, a Javascript test and a Python test). |\n| `duration` | \/\/optional float or int\/\/ | Runtime duration of the test, in seconds. |\n| `path` | \/\/optional string\/\/ | Path to the file where the test is declared, relative to the project root. |\n| `coverage` | \/\/optional map\u003cstring, wild\u003e\/\/ | Coverage information for this test. |\n| `details` | \/\/optional string\/\/ | Additional human-readable information about the failure. |\n\nThe `result` parameter recognizes these test results:\n\n| Key | Name | Description |\n|-------------|--------------|--------------|\n| `pass` | **Pass** | The test passed. |\n| `fail` | **Fail** | The test failed. |\n| `skip` | **Skip** | The test was not executed. |\n| `broken` | **Broken** | The test failed in an abnormal or severe way. For example, the harness crashed instead of reporting a failure. |\n| `unsound` | **Unsound** | The test failed, but this change is probably not what broke it. For example, it might have already been failing. |\n\nThis is a simple, valid value for the `unit` parameter. It reports one passing test and one failing test:\n\n\n\n```lang=json\n[\n {\n \"name\": \"PassingTest\",\n \"result\": \"pass\"\n },\n {\n \"name\": \"FailingTest\",\n \"result\": \"fail\"\n }\n]\n```\n\nLint Results\n============\nLike unit test results, you can report lint results alongside a message. The `lint` parameter should contain results as a list of dictionaries with these keys:\n\n| Key | Type | Description |\n|-------------|--------------|--------------|\n| `name` | \/\/string\/\/ | Short message name, like \"Syntax Error\". |\n| `code` | \/\/string\/\/ | Lint message code identifying the type of message, like \"ERR123\". |\n| `severity` | \/\/string\/\/ | Severity of the message. |\n| `path` | \/\/string\/\/ | Path to the file containing the lint message, from the project root. |\n| `line` | \/\/optional int\/\/ | Line number in the file where the text which triggered the message first appears. The first line of the file is line 1, not line 0. |\n| `char` | \/\/optional int\/\/ | Byte position on the line where the text which triggered the message starts. The first byte on the line is byte 1, not byte 0. This position is byte-based (not character-based) because not all lintable files have a valid character encoding. |\n| `description` | \/\/optional string\/\/ | Long explanation of the lint message. |\n\nThe `severity` parameter recognizes these severity levels:\n\n| Key | Name |\n|-------------|--------------|\n| `advice` | **Advice** |\n| `autofix` | **Auto-Fix** |\n| `warning` | **Warning** |\n| `error` | **Error** |\n| `disabled` | **Disabled** |\n\nThis is a simple, valid value for the `lint` parameter. It reports one error and one warning:\n\n```lang=json\n[\n {\n \"name\": \"Syntax Error\",\n \"code\": \"EXAMPLE1\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/example.c\",\n \"line\": 17,\n \"char\": 3\n },\n {\n \"name\": \"Not A Haiku\",\n \"code\": \"EXAMPLE2\",\n \"severity\": \"error\",\n \"path\": \"path\/to\/source.cpp\",\n \"line\": 23,\n \"char\": 1,\n \"description\": \"This function definition is not a haiku.\"\n }\n]\n```\n\n","params":{"buildTargetPHID":"required phid","type":"required string-constant\u003c\"pass\", \"fail\", \"work\"\u003e","unit":"optional list\u003cwild\u003e","lint":"optional list\u003cwild\u003e"},"return":"void"},"macro.query":{"description":"Retrieve image macro information.","params":{"authorPHIDs":"optional list\u003cphid\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cid\u003e","names":"optional list\u003cstring\u003e","nameLike":"optional string"},"return":"list\u003cdict\u003e"},"macro.creatememe":{"description":"Generate a meme.","params":{"macroName":"string","upperText":"optional string","lowerText":"optional string"},"return":"string"},"maniphest.createtask":{"description":"Create a new Maniphest task.","params":{"title":"required string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict"},"return":"nonempty dict"},"maniphest.gettasktransactions":{"description":"Retrieve Maniphest task transactions.","params":{"ids":"required list\u003cint\u003e"},"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"maniphest.info":{"description":"Retrieve information about a Maniphest task, given its ID.","params":{"task_id":"required id"},"return":"nonempty dict"},"maniphest.query":{"description":"Execute complex searches for Maniphest tasks.","params":{"ids":"optional list\u003cuint\u003e","phids":"optional list\u003cphid\u003e","ownerPHIDs":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","projectPHIDs":"optional list\u003cphid\u003e","ccPHIDs":"optional list\u003cphid\u003e","fullText":"optional string","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-resolved\", \"status-wontfix\", \"status-invalid\", \"status-spite\", \"status-duplicate\"\u003e","order":"optional string-constant\u003c\"order-priority\", \"order-created\", \"order-modified\"\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"maniphest.querystatuses":{"description":"Retrieve information about possible Maniphest task status values.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"maniphest.update":{"description":"Update an existing Maniphest task.","params":{"id":"optional int","phid":"optional int","title":"optional string","description":"optional string","ownerPHID":"optional phid","viewPolicy":"optional phid or policy string","editPolicy":"optional phid or policy string","ccPHIDs":"optional list\u003cphid\u003e","priority":"optional int","projectPHIDs":"optional list\u003cphid\u003e","auxiliary":"optional dict","status":"optional string","comments":"optional string"},"return":"nonempty dict"},"maniphest.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"maniphest.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"owners.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"owners.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"owners.query":{"description":"Query for Owners packages. Obsoleted by \"owners.search\".","params":{"userOwner":"optional string","projectOwner":"optional string","userAffiliated":"optional string","repositoryCallsign":"optional string","path":"optional string"},"return":"dict\u003cphid -\u003e dict of package info\u003e"},"passphrase.query":{"description":"Query credentials.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","needSecrets":"optional bool","needPublicKeys":"optional bool","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"paste.create":{"description":"Create a new paste.","params":{"content":"required string","title":"optional string","language":"optional string"},"return":"nonempty dict"},"paste.query":{"description":"Query Pastes.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","authorPHIDs":"optional list\u003cphid\u003e","after":"optional int","limit":"optional int, default = 100"},"return":"list\u003cdict\u003e"},"paste.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"paste.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"paste.info":{"description":"Retrieve an array of information about a paste.","params":{"paste_id":"required id"},"return":"nonempty dict"},"phame.blog.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"phame.blog.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"phame.post.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"phame.post.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"phid.lookup":{"description":"Look up objects by name.","params":{"names":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.query":{"description":"Retrieve information about arbitrary PHIDs.","params":{"phids":"required list\u003cphid\u003e"},"return":"nonempty dict\u003cstring, wild\u003e"},"phid.info":{"description":"Retrieve information about an arbitrary PHID.","params":{"phid":"required phid"},"return":"nonempty dict\u003cstring, wild\u003e"},"phragment.getpatch":{"description":"Retrieve the patches to apply for a given set of files.","params":{"path":"required string","state":"required dict\u003cstring, string\u003e"},"return":"nonempty dict"},"phragment.queryfragments":{"description":"Query fragments based on their paths.","params":{"paths":"required list\u003cstring\u003e"},"return":"nonempty dict"},"phriction.create":{"description":"Create a Phriction document.","params":{"slug":"required string","title":"required string","content":"required string","description":"optional string"},"return":"nonempty dict"},"phriction.edit":{"description":"Update a Phriction document.","params":{"slug":"required string","title":"optional string","content":"optional string","description":"optional string"},"return":"nonempty dict"},"phriction.history":{"description":"Retrieve history about a Phriction document.","params":{"slug":"required string"},"return":"nonempty list"},"phriction.info":{"description":"Retrieve information about a Phriction document.","params":{"slug":"required string"},"return":"nonempty dict"},"project.create":{"description":"Create a project.","params":{"name":"required string","members":"optional list\u003cphid\u003e","icon":"optional string","color":"optional string","tags":"optional list\u003cstring\u003e"},"return":"dict"},"project.query":{"description":"Execute searches for Projects.","params":{"ids":"optional list\u003cint\u003e","names":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","slugs":"optional list\u003cstring\u003e","icons":"optional list\u003cstring\u003e","colors":"optional list\u003cstring\u003e","status":"optional string-constant\u003c\"status-any\", \"status-open\", \"status-closed\", \"status-active\", \"status-archived\"\u003e","members":"optional list\u003cphid\u003e","limit":"optional int","offset":"optional int"},"return":"list"},"project.edit":{"description":"This is a standard **ApplicationEditor** method which allows you to create and modify objects by applying transactions. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Edit+Endpoints&type=article&jump=1 | Conduit API: Using Edit Endpoints ]]**.","params":{"transactions":"list\u003cmap\u003cstring, wild\u003e\u003e","objectIdentifier":"optional id|phid|string"},"return":"map\u003cstring, wild\u003e"},"project.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"releeph.getbranches":{"description":"Return information about all active Releeph branches.","params":[],"return":"nonempty list\u003cdict\u003cstring, wild\u003e\u003e"},"releeph.querybranches":{"description":"Query information about Releeph branches.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","productPHIDs":"optional list\u003cphid\u003e","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryproducts":{"description":"Query information about Releeph products.","params":{"ids":"optional list\u003cid\u003e","phids":"optional list\u003cphid\u003e","repositoryPHIDs":"optional list\u003cphid\u003e","isActive":"optional bool","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"query-results"},"releeph.queryrequests":{"description":"Return information about all Releeph requests linked to the given ids.","params":{"revisionPHIDs":"optional list\u003cphid\u003e","requestedCommitPHIDs":"optional list\u003cphid\u003e"},"return":"dict\u003cstring, wild\u003e"},"releeph.request":{"description":"Request a commit or diff to be picked to a branch.","params":{"branchPHID":"required string","things":"required list\u003cstring\u003e","fields":"dict\u003cstring, string\u003e"},"return":"dict\u003cstring, wild\u003e"},"releephwork.canpush":{"description":"Return whether the conduit user is allowed to push.","params":{"projectPHID":"required string"},"return":"bool"},"releephwork.getauthorinfo":{"description":"Return a string to use as the VCS author.","params":{"userPHID":"required string","vcsType":"required string"},"return":"nonempty string"},"releephwork.getbranch":{"description":"Return information to help checkout \/ cut a Releeph branch.","params":{"branchPHID":"required string"},"return":"dict\u003cstring, wild\u003e"},"releephwork.getbranchcommitmessage":{"description":"Get a commit message for committing a Releeph branch.","params":{"branchPHID":"required string"},"return":"nonempty string"},"releephwork.getcommitmessage":{"description":"Get commit message components for building a ReleephRequest commit message.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e"},"return":"dict\u003cstring, string\u003e"},"releephwork.nextrequest":{"description":"Return info required to cut a branch, and pick and revert ReleephRequests.","params":{"branchPHID":"required phid","seen":"required map\u003cstring, bool\u003e"},"return":""},"releephwork.record":{"description":"Record whether we committed a pick or revert to the upstream repository.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","commitIdentifier":"required string"},"return":"void"},"releephwork.recordpickstatus":{"description":"Record whether a pick or revert was successful or not.","params":{"requestPHID":"required string","action":"required string-constant\u003c\"pick\", \"revert\"\u003e","ok":"required bool","dryRun":"optional bool","details":"optional dict\u003cstring, wild\u003e"},"return":""},"remarkup.process":{"description":"Process text through remarkup in Phabricator context.","params":{"context":"required string-constant\u003c\"phriction\", \"maniphest\", \"differential\", \"phame\", \"feed\", \"diffusion\"\u003e","contents":"required list\u003cstring\u003e"},"return":"nonempty dict"},"repository.query":{"description":"Query repositories.","params":{"ids":"optional list\u003cint\u003e","phids":"optional list\u003cphid\u003e","callsigns":"optional list\u003cstring\u003e","vcsTypes":"optional list\u003cstring\u003e","remoteURIs":"optional list\u003cstring\u003e","uuids":"optional list\u003cstring\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"slowvote.info":{"description":"Retrieve an array of information about a poll.","params":{"poll_id":"required id"},"return":"nonempty dict"},"token.give":{"description":"Give or change a token.","params":{"tokenPHID":"phid|null","objectPHID":"phid"},"return":"void"},"token.given":{"description":"Query tokens given to objects.","params":{"authorPHIDs":"list\u003cphid\u003e","objectPHIDs":"list\u003cphid\u003e","tokenPHIDs":"list\u003cphid\u003e"},"return":"list\u003cdict\u003e"},"token.query":{"description":"Query tokens.","params":[],"return":"list\u003cdict\u003e"},"user.disable":{"description":"Permanently disable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.enable":{"description":"Re-enable specified users (admin only).","params":{"phids":"required list\u003cphid\u003e"},"return":"void"},"user.query":{"description":"Query users.","params":{"usernames":"optional list\u003cstring\u003e","emails":"optional list\u003cstring\u003e","realnames":"optional list\u003cstring\u003e","phids":"optional list\u003cphid\u003e","ids":"optional list\u003cuint\u003e","offset":"optional int","limit":"optional int (default = 100)"},"return":"list\u003cdict\u003e"},"user.whoami":{"description":"Retrieve information about the logged-in user.","params":[],"return":"nonempty dict\u003cstring, wild\u003e"},"user.search":{"description":"This is a standard **ApplicationSearch** method which will let you list, query, or search for objects. For documentation on these endpoints, see **[[ https:\/\/secure.phabricator.com\/diviner\/find\/?name=Conduit+API%3A+Using+Search+Endpoints&type=article&jump=1 | Conduit API: Using Search Endpoints ]]**.","params":{"queryKey":"optional string","constraints":"optional map\u003cstring, wild\u003e","attachments":"optional map\u003cstring, bool\u003e","order":"optional order","before":"optional string","after":"optional string","limit":"optional int (default = 100)"},"return":"map\u003cstring, wild\u003e"},"user.find":{"description":"Lookup PHIDs by username. Obsoleted by \"user.query\".","params":{"aliases":"required list\u003cstring\u003e"},"return":"nonempty dict\u003cstring, phid\u003e"}} \ No newline at end of file From f564b9b654700d95c1209b8f4d5b676e3d0b6e96 Mon Sep 17 00:00:00 2001 From: Kimberly Date: Tue, 1 May 2018 15:12:41 -0600 Subject: [PATCH 29/44] deprecated parameters are now set to optional --- phabricator/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index c90a460..da96345 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -170,6 +170,8 @@ def parse_interfaces(interfaces): param_type = 'string' elif info_piece == 'nonempty': optionality = 'required' + elif info_piece == 'deprecated': + optionality = 'optional' else: param_type = info_piece From 1fdd8e463391f991438598aaf40201c4fa8902bb Mon Sep 17 00:00:00 2001 From: Romuald Brunet Date: Fri, 22 Nov 2019 21:52:14 +0100 Subject: [PATCH 30/44] Load interfaces via pkgutil.get_data() (#52) This allows library to be used from a zip archive --- phabricator/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index da96345..4fea41e 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -21,6 +21,7 @@ import os.path import re import socket +import pkgutil import time from ._compat import ( @@ -37,8 +38,9 @@ # Default Phabricator interfaces INTERFACES = {} -with open(os.path.join(os.path.dirname(__file__), 'interfaces.json')) as fobj: - INTERFACES = json.load(fobj) +INTERFACES = json.loads( + pkgutil.get_data(__name__, 'interfaces.json') + .decode('utf-8')) # Load arc config From 0e2e77faf091d63ab23f37446d68d4c8ec2e8259 Mon Sep 17 00:00:00 2001 From: Jason Cox Date: Fri, 22 Nov 2019 12:53:03 -0800 Subject: [PATCH 31/44] Make sure connection is closed cleanly after use (#60) --- phabricator/__init__.py | 2 ++ phabricator/tests/test_phabricator.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 4fea41e..afcecaf 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -314,11 +314,13 @@ def validate_kwarg(key, target): # Make sure we got a 2xx response indicating success if not response.status >= 200 or not response.status < 300: + conn.close() raise httplib.HTTPException( 'Bad response status: {0}'.format(response.status) ) response_data = response.read() + conn.close() if isinstance(response_data, str): response = response_data else: diff --git a/phabricator/tests/test_phabricator.py b/phabricator/tests/test_phabricator.py index 9f6f99d..58034a8 100644 --- a/phabricator/tests/test_phabricator.py +++ b/phabricator/tests/test_phabricator.py @@ -56,6 +56,7 @@ def test_connect(self, mock_connection): RESPONSES['conduit.connect'] ) mock_obj.getresponse.return_value.status = 200 + mock_obj.close = mock.Mock() api = phabricator.Phabricator( username='test', @@ -67,6 +68,7 @@ def test_connect(self, mock_connection): keys = api._conduit.keys() self.assertIn('sessionKey', keys) self.assertIn('connectionID', keys) + mock_obj.close.assert_called_once_with() @mock.patch('phabricator.httplib.HTTPConnection') def test_user_whoami(self, mock_connection): @@ -108,6 +110,7 @@ def test_bad_status(self, mock_connection): mock_obj = mock_connection.return_value = mock.Mock() mock_obj.getresponse.return_value = mock.Mock() mock_obj.getresponse.return_value.status = 400 + mock_obj.close = mock.Mock() api = phabricator.Phabricator( username='test', @@ -118,6 +121,7 @@ def test_bad_status(self, mock_connection): with self.assertRaises(phabricator.httplib.HTTPException): api.user.whoami() + mock_obj.close.assert_called_once_with() @mock.patch('phabricator.httplib.HTTPConnection') def test_maniphest_find(self, mock_connection): From 483781e0d64208828747043996961c7a121b0a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeppe=20Vesterb=C3=A6k?= Date: Fri, 22 Nov 2019 22:00:28 +0100 Subject: [PATCH 32/44] Forward kwargs (#50) Co-authored-by: Jeppe Vesterbaek --- phabricator/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index afcecaf..488c43c 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -370,7 +370,7 @@ def __init__(self, username=None, certificate=None, host=None, self.clientDescription = socket.gethostname() + ':python-phabricator' self._conduit = None - super(Phabricator, self).__init__(self) + super(Phabricator, self).__init__(self, **kwargs) def _request(self, **kwargs): raise SyntaxError('You cannot call the Conduit API without a resource.') From 843166d730df357be678def97cbd3a5bf88d378c Mon Sep 17 00:00:00 2001 From: Fabien Date: Wed, 10 Jun 2020 12:12:59 +0200 Subject: [PATCH 33/44] Prevent Phabricator.token from shadowing the conduit token API Conduit token endpoints (`token.*`) cannot be called because `token` is alreay in the `Phabricator.__dict__` and shadows the interface methods. This can be prevented by renaming `token` into `conduit_token`. A test case is added to prevent shadowing to occur again. --- phabricator/__init__.py | 8 ++++---- phabricator/tests/test_phabricator.py | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 488c43c..19f7068 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -357,9 +357,9 @@ def __init__(self, username=None, certificate=None, host=None, raise ConfigurationError("No host found or provided.") current_host_config = defined_hosts.get(self.host, {}) - self.token = token if token else current_host_config.get('token') + self.conduit_token = token if token else current_host_config.get('token') - if self.token is None: + if self.conduit_token is None: self.username = username if username else current_host_config.get('user') self.certificate = certificate if certificate else current_host_config.get('cert') @@ -376,9 +376,9 @@ def _request(self, **kwargs): raise SyntaxError('You cannot call the Conduit API without a resource.') def connect(self): - if self.token: + if self.conduit_token: self._conduit = { - 'token': self.token + 'token': self.conduit_token } return diff --git a/phabricator/tests/test_phabricator.py b/phabricator/tests/test_phabricator.py index 58034a8..32d4d44 100644 --- a/phabricator/tests/test_phabricator.py +++ b/phabricator/tests/test_phabricator.py @@ -176,5 +176,13 @@ def test_map_param_type(self): complex_list_pair = 'list, string>>' self.assertEqual(phabricator.map_param_type(complex_list_pair), [tuple]) + def test_endpoint_shadowing(self): + shadowed_endpoints = [e for e in self.api.interface.keys() if e in self.api.__dict__] + self.assertEqual( + shadowed_endpoints, + [], + "The following endpoints are shadowed: {}".format(shadowed_endpoints) + ) + if __name__ == '__main__': unittest.main() From 2e960bf5b1fa4abfd01ae253fd7da09e0baa2faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Schr=C3=B6der?= Date: Fri, 25 Sep 2020 20:14:48 +0200 Subject: [PATCH 34/44] Replace httplib with requests Not that is really matters, but I also fixed the Phabricator URL in the tests (the url has to have a / at the end and typically the path is also /api/). Fixed setup.py so that it is possible to install the test requires. --- .travis.yml | 2 +- phabricator/__init__.py | 34 +++------- phabricator/_compat.py | 10 --- phabricator/tests/test_phabricator.py | 92 ++++++++++++--------------- setup.py | 7 +- 5 files changed, 55 insertions(+), 90 deletions(-) diff --git a/.travis.yml b/.travis.yml index 374e740..ca2bed1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: python python: - '2.7' - '3.5' -install: pip install . +install: pip install .[tests] script: python -m phabricator.tests.test_phabricator deploy: provider: pypi diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 19f7068..b01d167 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -23,9 +23,10 @@ import socket import pkgutil import time +import requests from ._compat import ( - MutableMapping, iteritems, string_types, httplib, urlparse, urlencode, + MutableMapping, iteritems, string_types, urlencode, ) @@ -290,43 +291,28 @@ def validate_kwarg(key, target): self.api.connect() kwargs['__conduit__'] = self.api._conduit - url = urlparse.urlparse(self.api.host) - if url.scheme == 'https': - conn = httplib.HTTPSConnection(url.netloc, timeout=self.api.timeout) - else: - conn = httplib.HTTPConnection(url.netloc, timeout=self.api.timeout) - - path = url.path + '%s.%s' % (self.method, self.endpoint) headers = { 'User-Agent': 'python-phabricator/%s' % str(self.api.clientVersion), 'Content-Type': 'application/x-www-form-urlencoded' } - body = urlencode({ + body = { "params": json.dumps(kwargs), "output": self.api.response_format - }) + } # TODO: Use HTTP "method" from interfaces.json - conn.request('POST', path, body, headers) - response = conn.getresponse() + path = '%s%s.%s' % (self.api.host, self.method, self.endpoint) + response = requests.post(path, data=body, headers=headers, timeout=self.api.timeout) # Make sure we got a 2xx response indicating success - if not response.status >= 200 or not response.status < 300: - conn.close() - raise httplib.HTTPException( - 'Bad response status: {0}'.format(response.status) + if not response.status_code >= 200 or not response.status_code < 300: + raise requests.exceptions.HTTPError( + 'Bad response status: {0}'.format(response.status_code) ) - response_data = response.read() - conn.close() - if isinstance(response_data, str): - response = response_data - else: - response = response_data.decode("utf-8") - - data = self._parse_response(response) + data = self._parse_response(response.text) return Result(data['result']) diff --git a/phabricator/_compat.py b/phabricator/_compat.py index 68138ea..c87f3a8 100644 --- a/phabricator/_compat.py +++ b/phabricator/_compat.py @@ -7,16 +7,6 @@ except ImportError: from collections import MutableMapping -try: - import httplib -except ImportError: - import http.client as httplib - -try: - import urlparse -except ImportError: - import urllib.parse as urlparse - try: from urllib import urlencode except ImportError: diff --git a/phabricator/tests/test_phabricator.py b/phabricator/tests/test_phabricator.py index 32d4d44..cad5a8e 100644 --- a/phabricator/tests/test_phabricator.py +++ b/phabricator/tests/test_phabricator.py @@ -3,20 +3,14 @@ except ImportError: import unittest -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -try: - import unittest.mock as mock -except ImportError: - import mock +import requests +import responses from pkg_resources import resource_string import json import phabricator +phabricator.ARCRC = {} # overwrite any arcrc that might be read RESPONSES = json.loads( @@ -40,7 +34,7 @@ def setUp(self): self.api = phabricator.Phabricator( username='test', certificate='test', - host='http://localhost' + host='http://localhost/api/' ) self.api.certificate = CERTIFICATE @@ -49,37 +43,32 @@ def test_generate_hash(self): hashed = self.api.generate_hash(token) self.assertEqual(hashed, 'f8d3bea4e58a2b2967d93d5b307bfa7c693b2e7f') - @mock.patch('phabricator.httplib.HTTPConnection') - def test_connect(self, mock_connection): - mock_obj = mock_connection.return_value = mock.Mock() - mock_obj.getresponse.return_value = StringIO( - RESPONSES['conduit.connect'] - ) - mock_obj.getresponse.return_value.status = 200 - mock_obj.close = mock.Mock() + @responses.activate + def test_connect(self): + responses.add('POST', 'http://localhost/api/conduit.connect', + body=RESPONSES['conduit.connect'], status=200) api = phabricator.Phabricator( username='test', certificate='test', - host='http://localhost' + host='http://localhost/api/' ) api.connect() keys = api._conduit.keys() self.assertIn('sessionKey', keys) self.assertIn('connectionID', keys) - mock_obj.close.assert_called_once_with() + assert len(responses.calls) == 1 - @mock.patch('phabricator.httplib.HTTPConnection') - def test_user_whoami(self, mock_connection): - mock_obj = mock_connection.return_value = mock.Mock() - mock_obj.getresponse.return_value = StringIO(RESPONSES['user.whoami']) - mock_obj.getresponse.return_value.status = 200 + @responses.activate + def test_user_whoami(self): + responses.add('POST', 'http://localhost/api/user.whoami', + body=RESPONSES['user.whoami'], status=200) api = phabricator.Phabricator( username='test', certificate='test', - host='http://localhost' + host='http://localhost/api/' ) api._conduit = True @@ -89,7 +78,7 @@ def test_classic_resources(self): api = phabricator.Phabricator( username='test', certificate='test', - host='http://localhost' + host='http://localhost/api/' ) self.assertEqual(api.user.whoami.method, 'user') @@ -99,42 +88,37 @@ def test_nested_resources(self): api = phabricator.Phabricator( username='test', certificate='test', - host='http://localhost' + host='http://localhost/api/' ) self.assertEqual(api.diffusion.repository.edit.method, 'diffusion') - self.assertEqual(api.diffusion.repository.edit.endpoint, 'repository.edit') + self.assertEqual( + api.diffusion.repository.edit.endpoint, 'repository.edit') - @mock.patch('phabricator.httplib.HTTPConnection') - def test_bad_status(self, mock_connection): - mock_obj = mock_connection.return_value = mock.Mock() - mock_obj.getresponse.return_value = mock.Mock() - mock_obj.getresponse.return_value.status = 400 - mock_obj.close = mock.Mock() + @responses.activate + def test_bad_status(self): + responses.add( + 'POST', 'http://localhost/api/conduit.connect', status=400) api = phabricator.Phabricator( - username='test', - certificate='test', - host='http://localhost' + username='test', + certificate='test', + host='http://localhost/api/' ) - api._conduit = True - with self.assertRaises(phabricator.httplib.HTTPException): + with self.assertRaises(requests.exceptions.HTTPError): api.user.whoami() - mock_obj.close.assert_called_once_with() + assert len(responses.calls) == 1 - @mock.patch('phabricator.httplib.HTTPConnection') - def test_maniphest_find(self, mock_connection): - mock_obj = mock_connection.return_value = mock.Mock() - mock_obj.getresponse.return_value = StringIO( - RESPONSES['maniphest.find'] - ) - mock_obj.getresponse.return_value.status = 200 + @responses.activate + def test_maniphest_find(self): + responses.add('POST', 'http://localhost/api/maniphest.find', + body=RESPONSES['maniphest.find'], status=200) api = phabricator.Phabricator( username='test', certificate='test', - host='http://localhost' + host='http://localhost/api/' ) api._conduit = True @@ -165,16 +149,18 @@ def test_validation(self): def test_map_param_type(self): uint = 'uint' - self.assertEqual(phabricator.map_param_type(uint), int) + self.assertEqual(phabricator.map_param_type(uint), int) list_bool = 'list' - self.assertEqual(phabricator.map_param_type(list_bool), [bool]) + self.assertEqual(phabricator.map_param_type(list_bool), [bool]) list_pair = 'list>' - self.assertEqual(phabricator.map_param_type(list_pair), [tuple]) + self.assertEqual(phabricator.map_param_type(list_pair), [tuple]) complex_list_pair = 'list, string>>' - self.assertEqual(phabricator.map_param_type(complex_list_pair), [tuple]) + self.assertEqual(phabricator.map_param_type( + complex_list_pair), [tuple]) + def test_endpoint_shadowing(self): shadowed_endpoints = [e for e in self.api.interface.keys() if e in self.api.__dict__] diff --git a/setup.py b/setup.py index bff54d5..51d1386 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import setup, find_packages -tests_requires = [] +tests_requires = ['responses>=0.12'] if sys.version_info[:2] < (2, 7): tests_requires.append('unittest2') @@ -21,8 +21,11 @@ description='Phabricator API Bindings', packages=find_packages(), zip_safe=False, + install_requires=['requests>=2.22'], test_suite='phabricator.tests.test_phabricator', - tests_require=tests_requires, + extras_require={ + 'tests': tests_requires, + }, include_package_data=True, classifiers=[ 'Intended Audience :: Developers', From a922ba404a4578f9f909e241539b1fb5a99585b2 Mon Sep 17 00:00:00 2001 From: thekashifmalik Date: Fri, 13 Nov 2020 03:20:49 -0800 Subject: [PATCH 35/44] 0.8.0 --- CHANGES | 9 +++++++++ setup.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 5f8d0bf..2fd4c34 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +0.8.0 + +* Switch to using requests +* Allow library to be used from a zip archive +* Deprecated parameters are now set to optional +* Fixed bug where instance attribute was shadowing API endpoint +* Update interfaces.json +* Update README + 0.7.0 * Allow for nested methods to support conduit calls such as diffusion.repository.edit diff --git a/setup.py b/setup.py index 51d1386..c7586bc 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name='phabricator', - version='0.7.0', + version='0.8.0', author='Disqus', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator', From f01dad32ff9784f27304d1bbb93f4c1bb10ad92b Mon Sep 17 00:00:00 2001 From: Nick Powell <184579+nmpowell@users.noreply.github.com> Date: Tue, 9 Feb 2021 00:53:33 +0000 Subject: [PATCH 36/44] resolve conflict between Resource .interface attr and Almanac interface endpoints --- phabricator/__init__.py | 8 ++++---- phabricator/tests/test_phabricator.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index b01d167..6d53748 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -224,7 +224,7 @@ def __repr__(self): class Resource(object): def __init__(self, api, interface=None, endpoint=None, method=None, nested=False): self.api = api - self.interface = interface or copy.deepcopy(parse_interfaces(INTERFACES)) + self._interface = interface or copy.deepcopy(parse_interfaces(INTERFACES)) self.endpoint = endpoint self.method = method self.nested = nested @@ -232,7 +232,7 @@ def __init__(self, api, interface=None, endpoint=None, method=None, nested=False def __getattr__(self, attr): if attr in getattr(self, '__dict__'): return getattr(self, attr) - interface = self.interface + interface = self._interface if self.nested: attr = "%s.%s" % (self.endpoint, attr) submethod_exists = False @@ -254,7 +254,7 @@ def __call__(self, **kwargs): def _request(self, **kwargs): # Check for missing variables - resource = self.interface + resource = self._interface def validate_kwarg(key, target): # Always allow list @@ -391,4 +391,4 @@ def update_interfaces(self): interfaces = query() - self.interface = parse_interfaces(interfaces) + self._interface = parse_interfaces(interfaces) diff --git a/phabricator/tests/test_phabricator.py b/phabricator/tests/test_phabricator.py index cad5a8e..e12b285 100644 --- a/phabricator/tests/test_phabricator.py +++ b/phabricator/tests/test_phabricator.py @@ -163,7 +163,7 @@ def test_map_param_type(self): def test_endpoint_shadowing(self): - shadowed_endpoints = [e for e in self.api.interface.keys() if e in self.api.__dict__] + shadowed_endpoints = [e for e in self.api._interface.keys() if e in self.api.__dict__] self.assertEqual( shadowed_endpoints, [], From afe257ca766ac9ecf0c9554d43f62a7997e32ae7 Mon Sep 17 00:00:00 2001 From: Nick Powell <184579+nmpowell@users.noreply.github.com> Date: Tue, 9 Feb 2021 21:23:10 +0000 Subject: [PATCH 37/44] bumped version --- CHANGES | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 2fd4c34..64c95a0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.8.1 + +* Fixed bug where built-in interface dict overwrote `interface` methods from Almanac (`interface.search`, `interface.edit`). The `Resource` attribute `interface` is renamed `_interface`. + 0.8.0 * Switch to using requests diff --git a/setup.py b/setup.py index c7586bc..ec3f0e5 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name='phabricator', - version='0.8.0', + version='0.8.1', author='Disqus', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator', From 876265275a5b202d4b3a8c3062540f6d76dbca6b Mon Sep 17 00:00:00 2001 From: thekashifmalik Date: Tue, 23 Feb 2021 15:22:16 -0800 Subject: [PATCH 38/44] Add bin executable to publish package --- bin/publish | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 bin/publish diff --git a/bin/publish b/bin/publish new file mode 100755 index 0000000..bf15421 --- /dev/null +++ b/bin/publish @@ -0,0 +1,4 @@ +#!/bin/bash +set -eo pipefail +python setup.py sdist bdist_wheel +twine upload dist/* \ No newline at end of file From ca27b401bc4c93b3c9025fb81e945d5bfd2556de Mon Sep 17 00:00:00 2001 From: mmolinaro Date: Wed, 6 Apr 2022 22:49:14 +0000 Subject: [PATCH 39/44] Add default retry to phab APIs --- phabricator/__init__.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 6d53748..3b6f26a 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -24,6 +24,7 @@ import pkgutil import time import requests +from requests.adapters import HTTPAdapter, Retry from ._compat import ( MutableMapping, iteritems, string_types, urlencode, @@ -228,6 +229,16 @@ def __init__(self, api, interface=None, endpoint=None, method=None, nested=False self.endpoint = endpoint self.method = method self.nested = nested + self.session = requests.Session() + retry_strategy = Retry( + total=5, + status_forcelist=[429, 500, 502, 503, 504], + method_whitelist=["HEAD", "GET", "OPTIONS"] + ) + adapter = HTTPAdapter(max_retries=retry_strategy) + self.session.mount("https://", adapter) + self.session.mount("http://", adapter) + def __getattr__(self, attr): if attr in getattr(self, '__dict__'): @@ -304,7 +315,7 @@ def validate_kwarg(key, target): # TODO: Use HTTP "method" from interfaces.json path = '%s%s.%s' % (self.api.host, self.method, self.endpoint) - response = requests.post(path, data=body, headers=headers, timeout=self.api.timeout) + response = self.session.post(path, data=body, headers=headers, timeout=self.api.timeout) # Make sure we got a 2xx response indicating success if not response.status_code >= 200 or not response.status_code < 300: From 6ba4226e0f9679681a0277602414faf2f46e2d55 Mon Sep 17 00:00:00 2001 From: mmolinaro Date: Wed, 6 Apr 2022 22:54:26 +0000 Subject: [PATCH 40/44] better options --- phabricator/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 3b6f26a..6dcd4be 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -231,9 +231,9 @@ def __init__(self, api, interface=None, endpoint=None, method=None, nested=False self.nested = nested self.session = requests.Session() retry_strategy = Retry( - total=5, - status_forcelist=[429, 500, 502, 503, 504], - method_whitelist=["HEAD", "GET", "OPTIONS"] + total=3, + connect=3, + method_whitelist=["HEAD", "GET", "POST", "PATCH", "PUT", "OPTIONS"] ) adapter = HTTPAdapter(max_retries=retry_strategy) self.session.mount("https://", adapter) From af4f8e9fedc77a62ee6aacb52a428e5c958beb51 Mon Sep 17 00:00:00 2001 From: Mark Molinaro Date: Thu, 7 Apr 2022 22:39:00 +0000 Subject: [PATCH 41/44] inline retry strat --- phabricator/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/phabricator/__init__.py b/phabricator/__init__.py index 6dcd4be..9277efa 100644 --- a/phabricator/__init__.py +++ b/phabricator/__init__.py @@ -230,12 +230,11 @@ def __init__(self, api, interface=None, endpoint=None, method=None, nested=False self.method = method self.nested = nested self.session = requests.Session() - retry_strategy = Retry( + adapter = HTTPAdapter(max_retries=Retry( total=3, connect=3, - method_whitelist=["HEAD", "GET", "POST", "PATCH", "PUT", "OPTIONS"] - ) - adapter = HTTPAdapter(max_retries=retry_strategy) + allowed_methods=["HEAD", "GET", "POST", "PATCH", "PUT", "OPTIONS"] + )) self.session.mount("https://", adapter) self.session.mount("http://", adapter) From de52b7d520e622327240697e8cadf63a64d69589 Mon Sep 17 00:00:00 2001 From: thekashifmalik Date: Thu, 7 Apr 2022 15:49:44 -0700 Subject: [PATCH 42/44] Bump versions for new release --- CHANGES | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 64c95a0..ca9edfa 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.9.0 + +* Add default retry to API calls. + 0.8.1 * Fixed bug where built-in interface dict overwrote `interface` methods from Almanac (`interface.search`, `interface.edit`). The `Resource` attribute `interface` is renamed `_interface`. diff --git a/setup.py b/setup.py index ec3f0e5..401bf55 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name='phabricator', - version='0.8.1', + version='0.9.0', author='Disqus', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator', From da00db4ea16e462b0c09bb1ade57e4b74dec76ac Mon Sep 17 00:00:00 2001 From: Mark Molinaro Date: Tue, 12 Apr 2022 22:31:42 +0000 Subject: [PATCH 43/44] Fix requests version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 401bf55..19d2b63 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ description='Phabricator API Bindings', packages=find_packages(), zip_safe=False, - install_requires=['requests>=2.22'], + install_requires=['requests>=2.26'], test_suite='phabricator.tests.test_phabricator', extras_require={ 'tests': tests_requires, From 66190f9065dc68f3bba35c5fcbd0b6baf567b95d Mon Sep 17 00:00:00 2001 From: thekashifmalik Date: Thu, 14 Apr 2022 18:23:34 -0700 Subject: [PATCH 44/44] Bump version for release --- CHANGES | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index ca9edfa..8652a4e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.9.1 + +* Update requests version. + 0.9.0 * Add default retry to API calls. diff --git a/setup.py b/setup.py index 19d2b63..3ec4f1a 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name='phabricator', - version='0.9.0', + version='0.9.1', author='Disqus', author_email='opensource@disqus.com', url='http://github.com/disqus/python-phabricator',