Skip to content
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

fix: try two public urls for maintainer exists lint #2171

Merged
merged 5 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions conda_smithy/lint_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,16 +413,44 @@ def _maintainer_exists(maintainer: str) -> bool:
gh = _cached_gh()
try:
gh.get_user(maintainer)
is_user = True
except github.UnknownObjectException:
return False

This comment was marked as spam.

return True

This comment was marked as spam.

is_user = False

# for w/e reason, the user endpoint returns an entry for orgs
# however the org endpoint does not return an entry for users
# so we have to check both
try:
gh.get_organization(maintainer)
is_org = True
except github.UnknownObjectException:
is_org = False
else:
return (
requests.get(
f"https://api.github.com/users/{maintainer}"

This comment was marked as spam.

).status_code
== 200
# this API request has no token and so has a restrictive rate limit
# return (
# requests.get(
# f"https://api.github.com/users/{maintainer}"
# ).status_code
# == 200
# )
# so we check two public URLs instead.
# 1. github.com/<maintainer>?tab=repositories - this URL works for all users and all orgs
# 2. https://github.com/orgs/<maintainer>/teams - this URL only works for
# orgs so we make sure it fails
# we do not allow redirects to ensure we get the correct status code
# for the specific URL we requested
req_profile = requests.get(
f"https://github.com/{maintainer}?tab=repositories",
allow_redirects=False,
)
is_user = req_profile.status_code == 200
req_org = requests.get(
f"https://github.com/orgs/{maintainer}/teams",
allow_redirects=False,
)
is_org = req_org.status_code == 200

return is_user and not is_org


@lru_cache(maxsize=1)
Expand Down
24 changes: 24 additions & 0 deletions news/2171-fix-maintainer_exists.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
**Added:**

* <news item>

**Changed:**

* <news item>

**Deprecated:**

* <news item>

**Removed:**

* <news item>

**Fixed:**

* Fixed a bug in checking in recipe maintainers exist without a GitHub token
where the anonymous API would run out of requests. (#2171)

**Security:**

* <news item>
36 changes: 36 additions & 0 deletions tests/test_lint_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,42 @@ def test_maintainer_exists(self):
expected_message = 'Recipe maintainer "isuruf" does not exist'
self.assertNotIn(expected_message, lints)

lints, _ = linter.lintify_meta_yaml(
{"extra": {"recipe-maintainers": ["conda-forge"]}},
conda_forge=True,
)
expected_message = 'Recipe maintainer "conda-forge" does not exist'
self.assertIn(expected_message, lints)

def test_maintainer_exists_no_token(self):
gh_token = os.environ.get("GH_TOKEN", None)
try:
if "GH_TOKEN" in os.environ:
del os.environ["GH_TOKEN"]

lints, _ = linter.lintify_meta_yaml(
{"extra": {"recipe-maintainers": ["support"]}},
conda_forge=True,
)
expected_message = 'Recipe maintainer "support" does not exist'
self.assertIn(expected_message, lints)

lints, _ = linter.lintify_meta_yaml(
{"extra": {"recipe-maintainers": ["isuruf"]}}, conda_forge=True
)
expected_message = 'Recipe maintainer "isuruf" does not exist'
self.assertNotIn(expected_message, lints)

lints, _ = linter.lintify_meta_yaml(
{"extra": {"recipe-maintainers": ["conda-forge"]}},
conda_forge=True,
)
expected_message = 'Recipe maintainer "conda-forge" does not exist'
self.assertIn(expected_message, lints)
finally:
if gh_token is not None:
os.environ["GH_TOKEN"] = gh_token

def test_maintainer_team_exists(self):
lints, _ = linter.lintify_meta_yaml(
{
Expand Down