Skip to content

Commit 1bb67da

Browse files
authored
Merges #899 Closes #899 Fixes #898
2 parents 5da67cf + 3aa90ed commit 1bb67da

3 files changed

Lines changed: 95 additions & 2 deletions

File tree

perceval/backends/core/github.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,9 +1040,13 @@ def _read_pem(self):
10401040
return private_key
10411041

10421042
def _get_installation_id(self, headers):
1043-
"""Get installation ID given the GitHub login
1043+
"""Return the GitHub App installation ID for the configured owner.
10441044
1045-
:param headers: request headers with JWT token
1045+
For private repositories, the installation must match the owner.
1046+
For public repositories, any available installation ID is sufficient.
1047+
1048+
If no installation matches the owner, the first available installation
1049+
is returned (if any).
10461050
10471051
:returns: Installation ID
10481052
"""
@@ -1054,6 +1058,10 @@ def _get_installation_id(self, headers):
10541058
if i['account']['login'] == self.owner:
10551059
installation_id = i['id']
10561060
break
1061+
1062+
if not installation_id and data:
1063+
installation_id = data[0]['id']
1064+
10571065
return installation_id
10581066

10591067
def _create_access_token(self, headers, installation_id):
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
title: GitHub App token for public repositories
3+
category: fixed
4+
author: Jose Javier Merchante <jjmerchante@bitergia.com>
5+
issue: 898
6+
notes: >
7+
When no matching GitHub App installation is available for a repository,
8+
Perceval now falls back to using another installation token to retrieve
9+
public data.

tests/test_github.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3723,6 +3723,82 @@ def test_enterprise_repo(self):
37233723

37243724
self.assertEqual(httpretty.last_request().headers["Authorization"], "token aaa")
37253725

3726+
@httpretty.activate
3727+
def test_get_installation_id(self):
3728+
"""Test installation ID lookup for the matching owner"""
3729+
3730+
rate_limit = read_file("data/github/rate_limit")
3731+
3732+
httpretty.register_uri(
3733+
httpretty.GET,
3734+
GITHUB_RATE_LIMIT,
3735+
body=rate_limit,
3736+
status=200,
3737+
forcing_headers={"X-RateLimit-Remaining": "20", "X-RateLimit-Reset": "15"},
3738+
)
3739+
3740+
client = GitHubClient(
3741+
"zhquan_example",
3742+
"repo",
3743+
[],
3744+
github_app_id="1",
3745+
github_app_pk_filepath="data/github/private.pem",
3746+
from_archive=True,
3747+
)
3748+
3749+
installations = [
3750+
{"account": {"login": "other_owner"}, "id": "7"},
3751+
{"account": {"login": "zhquan_example"}, "id": "8"},
3752+
]
3753+
response = unittest.mock.Mock()
3754+
response.json.return_value = installations
3755+
client.session.get = unittest.mock.Mock(return_value=response)
3756+
3757+
installation_id = client._get_installation_id({"Authorization": "Bearer token"})
3758+
3759+
self.assertEqual(installation_id, "8")
3760+
client.session.get.assert_called_once_with(
3761+
GITHUB_APP_INSTALLATION_URL, headers={"Authorization": "Bearer token"}
3762+
)
3763+
3764+
@httpretty.activate
3765+
def test_get_installation_id_fallback(self):
3766+
"""Test installation ID lookup fallback for public repositories"""
3767+
3768+
rate_limit = read_file("data/github/rate_limit")
3769+
3770+
httpretty.register_uri(
3771+
httpretty.GET,
3772+
GITHUB_RATE_LIMIT,
3773+
body=rate_limit,
3774+
status=200,
3775+
forcing_headers={"X-RateLimit-Remaining": "20", "X-RateLimit-Reset": "15"},
3776+
)
3777+
3778+
client = GitHubClient(
3779+
"public_owner",
3780+
"repo",
3781+
[],
3782+
github_app_id="1",
3783+
github_app_pk_filepath="data/github/private.pem",
3784+
from_archive=True,
3785+
)
3786+
3787+
installations = [
3788+
{"account": {"login": "other_owner"}, "id": "7"},
3789+
{"account": {"login": "another_owner"}, "id": "8"},
3790+
]
3791+
response = unittest.mock.Mock()
3792+
response.json.return_value = installations
3793+
client.session.get = unittest.mock.Mock(return_value=response)
3794+
3795+
installation_id = client._get_installation_id({"Authorization": "Bearer token"})
3796+
3797+
self.assertEqual(installation_id, "7")
3798+
client.session.get.assert_called_once_with(
3799+
GITHUB_APP_INSTALLATION_URL, headers={"Authorization": "Bearer token"}
3800+
)
3801+
37263802
@httpretty.activate
37273803
def test_get_from_date_issues(self):
37283804
"""Test issues from date API call"""

0 commit comments

Comments
 (0)