-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add API endpoint to get a Phabricator Revision from Lando #4
Conversation
landoapi/api/revisions.py
Outdated
phab = Phabricator(host=os.getenv('PHABRICATOR_URL'), | ||
token=os.getenv('PHABRICATOR_API_KEY')) | ||
phab.update_interfaces() | ||
return phab |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line?
landoapi/api/revisions.py
Outdated
id_num = id.strip().replace('D', '') | ||
phab = get_phabricator_client() | ||
response = phab.differential.query(ids=[id_num]) | ||
if response and response[0]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's call this "revisions"; response makes me think of a network request, which it may be, but seems like it could be confusing.
landoapi/conduit.py
Outdated
|
||
|
||
def get_revision(id=None, phid=None, **kwargs): | ||
id_num = id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use revision_id
cd3b036
to
e19fec3
Compare
The stubs to create the app and versionfile in tests/test_app.py would also be needed in every other test file that wanted to test the Flask app. This commit extracts those utility functions into their own file which can be imported into any test that needs them. This commit also renames 'test_app.py' to 'tests_dockerflow.py' to better represent what that file is testing.
e19fec3
to
631991d
Compare
This PR has changed significantly and will require a new fresh review. |
This PR also assumes we will be passing the user's api key instead of using Oauth + an api key specifically for Lando. We cannot do the latter because Phabricator doesn't provide a way to actually check a user's permission to see a revision via its API. |
landoapi/api/revisions.py
Outdated
from landoapi.phabricator_client import PhabricatorClient | ||
|
||
|
||
def get(api_key, id): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't hate me but can we make this param revision_id
? id
isn't descriptive and requires searching to find out what it represents
a7a6d5d
to
b6fb5ca
Compare
Updated this with tests, highly recommend that you view the diff by commits instead of the whole thing at once. See the PR summary for how to test all this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's some clean code, nice work! We just need to address the potential OSS license mixing.
@@ -0,0 +1,109 @@ | |||
# This Source Code Form is subject to the terms of the Mozilla Public |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the file from python-phabricator
? That project says it's licensed under Apache 2.0. If this code is from that project, then our project becomes a mixed-license work (not a bad thing), which means we should include a NOTICE file in the project root that contains the Apache 2.0 license text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, as you see in the comments above I decided against using any library since making the requests ourselves was actually pretty simple and it makes our testing story a lot easier with requests-mock. So this is a file that I wrote.
tests/test_phabricator_client.py
Outdated
|
||
def test_get_revision_returns_200(): | ||
|
||
def test_get_revision_with_200_response(): | ||
phab = PhabricatorClient(api_key='api-key') | ||
api_url = '%s/api/differential.query' % os.getenv('PHABRICATOR_URL') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Part of the api_url line can be refactored into a fixture:
@pytest.fixture
def base_url():
return '{}/api/'.format(os.getenv('PHABRICATOR_URL))
def test_myapi(base_url):
api_url = base_url + 'foo.query'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea!
b6fb5ca
to
dabac5d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! Just some minor style cleanup.
landoapi/phabricator_client.py
Outdated
result = self.__get('/phid.query', {'phids[]': [phid]}) | ||
return result.get(phid) if result else None | ||
|
||
def __request(self, url, data=None, params=None, method='GET'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method name should be preceded by a single underscore.
landoapi/phabricator_client.py
Outdated
|
||
return response.get('result') | ||
|
||
def __get(self, url, data=None, params=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method name should be preceded by a single underscore. I also find overloading the name get()
a bit of a mind twist - doing so is rare in Python because of get
's special status. You might want to use a different method name, like _do_get()
or _GET()
.
landoapi/phabricator_client.py
Outdated
def __get(self, url, data=None, params=None): | ||
return self.__request(url, data, params, 'GET') | ||
|
||
def __post(self, url, data=None, params=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, should be single underscore.
landoapi/phabricator_client.py
Outdated
import requests | ||
|
||
|
||
class PhabricatorAPIException(Exception): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exception definitions should be at the bottom of the file, after classes.
1496b8e
to
1df11fc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one small comment but looks great!
landoapi/phabricator_client.py
Outdated
result = self._GET('/differential.query', {'ids[]': [id_num]}) | ||
elif phid: | ||
result = self._GET('/differential.query', {'phids[]': [phid]}) | ||
else: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this else
, can you just initialize result
to None
? Wont the return ternary take care of the return value?
This commit adds a utility class found in phabricator_client.py that abstracts the interface to Phabricator's Conduit API. Currently it supports querying revisions, users, and repos. As Phabricator's API changes, we can take care of those changes in this class without having to rewrite all of our other methods and api endpoints. Using the newly created class, this commit also adds a new api endpoint /revisions/{id} which returns details about a revision given an id. See the updated spec/swagger.yml for more details about this endpoint.
This commit adds unit tests for the PhabricatorClient and /revisions/{id} endpoint using the requests_mock library to stub out Phabricator's API responses. A new folder, `canned_responses` is added to contain example responses returned by the different services we depend on in our unit tests.
1df11fc
to
3485025
Compare
(Note: this is a larger PR and it may help to view the changes for each commit separately)
Refactor tests to reduce duplication
The stubs to create the app and versionfile in tests/test_app.py would also be needed in every other test file that wanted to test the Flask app. This commit extracts those utility functions into their own file which can be imported into any test that needs them. This commit also renames 'test_app.py' to 'tests_dockerflow.py' to better represent what that file is testing.
This is based on what David Walsh did in mozilla-conduit/lando-ui, thanks!
Add API enpoint to query a revision using the new Phabricator Client.
This commit adds a utility class found in phabricator_client.py that abstracts the interface to Phabricator's Conduit API. Currently it supports querying revisions, users, and repos. As Phabricator's API changes, we can take care of those changes in this class without having to rewrite all of our other methods and api endpoints.
Using the newly created class, this commit also adds a new api endpoint
/revisions/{id}
which returns details about a revision given an id. See the updated spec/swagger.yml for more details about this endpoint.Add tests for the PhabricatorClient and /revisions/{id} endpoint
This commit adds unit tests for the PhabricatorClient and /revisions/{id} endpoint using the requests_mock library to stub out Phabricator's API responses.
A new folder,
canned_responses
is added to contain example responses returned by the different services we depend on in our unit tests.How to test this PR
docker-compose up --build
to refresh your images.invoke test
to test the updated tests.docker-compose up
again to start the API server. Once running, visityour-docker-ip:8888
which will take you to the OpenAPI index page which allows you to test out the api directly. Currently, the project is setup to query the Phabricator instance at https://mozphab.dev.mozaws.net/. You can test querying https://mozphab.dev.mozaws.net/D1 by inputting1
for the id field and your phabricator API key (on the mozphab.dev instance). Inspect the result to confirm it is all working properly.(This PR is now complete)