Skip to content

Conversation

@anirudhprmar
Copy link
Contributor

Proposed change

Resolves #2887

The problem was totalCount didn't matched the required regular expression ^[_a-z][_a-z0-9]*$, meaning it wasn't snake_case as python supports that. When trying to solve for this issue, i renamed all the files using totalCount as field name but when i ran make check-test, i was getting some additional unnecessary error. I went deep and found out that PyGithub utilization in repository.test file was giving run time errors as according to docs PyGithub intentionally uses camelCase for totalCount to match GitHub's JSON response patterns, even though it breaks Python conventions.

To solve this there were only 2 ways:

  1. either to keep the total_count that'll fix the linting issue and keep totalCount too, for PyGithub compatibility.
  2. use getattr(commits, 'totalCount', 0) dynamically wherever we've used PyGithub library.

So, I implemented the first solution. Willing to hear suggestions on what should be done, keep it as it as or go with getattr().

Checklist

  • I read and followed the contributing guidelines
  • I ran make check-test locally and all tests passed
  • I used AI for code, documentation, or tests in this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 14, 2025

Summary by CodeRabbit

  • Refactor
    • Updated internal attribute naming conventions across GitHub API integration components, including user and repository synchronization, organization management, and data model handling, to improve code consistency and maintainability.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

This PR implements a systematic rename of the totalCount attribute to total_count across GitHub API response handling. The refactoring updates management commands, model layer code, and corresponding test files to align with Python's snake_case naming convention (PEP 8).

Changes

Cohort / File(s) Summary
Management Commands Using GitHub API
backend/apps/github/management/commands/github_sync_user.py, backend/apps/github/management/commands/github_update_owasp_organization.py, backend/apps/github/management/commands/github_update_related_organizations.py
Updated all GitHub API attribute access from totalCount to total_count in repository, pull request, issue, and commit count checks; updated corresponding logging and stdout messages.
Model Layer
backend/apps/github/models/repository.py
Changed attribute access from totalCount to total_count when handling GitHub API counts for commits and contributors in the from_github method.
Test Suite
backend/tests/apps/github/management/commands/github_sync_user_test.py, backend/tests/apps/github/management/commands/github_update_owasp_organization_test.py, backend/tests/apps/github/management/commands/github_update_related_organizations_test.py, backend/tests/apps/github/models/repository_test.py
Updated mock PaginatedList and test fixtures to use total_count instead of totalCount; added total_count attribute to mock objects and updated test assertions accordingly.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Homogeneous refactoring pattern applied consistently across all files
  • No logic, control flow, or error handling changes
  • Straightforward attribute rename verification needed across multiple files

Possibly related PRs

Suggested labels

backend, backend-tests

Suggested reviewers

  • arkid15r
  • kasya

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing the naming convention by converting totalCount to snake_case.
Description check ✅ Passed The description clearly explains the problem, the two considered solutions, and the implemented approach with justification.
Linked Issues check ✅ Passed The PR addresses issue #2887 by renaming totalCount to total_count across all relevant files while maintaining PyGithub compatibility.
Out of Scope Changes check ✅ Passed All changes directly address the naming convention requirement from issue #2887; no out-of-scope modifications are present.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

✨ Issue Enrichment is now available for GitHub issues!

CodeRabbit can now help you manage issues more effectively:

  • Duplicate Detection — Identify similar or duplicate issues
  • Related Issues & PRs — Find relevant issues and PR's from your repository
  • Suggested Assignees — Find the best person to work on the issue
  • Implementation Planning — Generate detailed coding plans for engineers and agents
Disable automatic issue enrichment

To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

issue_enrichment:
  auto_enrich:
    enabled: false

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/tests/apps/github/models/repository_test.py (1)

125-129: Test mock should match PyGithub's actual API.

The mock uses total_count, but PyGithub's actual PaginatedList has totalCount. While tests can mock any attribute, this creates a discrepancy between test and production behavior.

For consistency with PyGithub's API, consider:

-        type(commits_mock).total_count = PropertyMock(
+        type(commits_mock).totalCount = PropertyMock(
             side_effect=GithubException(
                 status=409, data={"message": "Git Repository is empty", "status": "409"}
             )
         )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 670fdff and 52cfb88.

📒 Files selected for processing (8)
  • backend/apps/github/management/commands/github_sync_user.py (9 hunks)
  • backend/apps/github/management/commands/github_update_owasp_organization.py (1 hunks)
  • backend/apps/github/management/commands/github_update_related_organizations.py (1 hunks)
  • backend/apps/github/models/repository.py (1 hunks)
  • backend/tests/apps/github/management/commands/github_sync_user_test.py (1 hunks)
  • backend/tests/apps/github/management/commands/github_update_owasp_organization_test.py (3 hunks)
  • backend/tests/apps/github/management/commands/github_update_related_organizations_test.py (1 hunks)
  • backend/tests/apps/github/models/repository_test.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
backend/apps/github/models/repository.py (1)
backend/apps/owasp/api/internal/nodes/committee.py (1)
  • contributors_count (15-17)

direction="desc",
)
gh_repositories_count = gh_repositories.totalCount # type: ignore[attr-defined]
gh_repositories_count = gh_repositories.total_count # type: ignore[attr-defined]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: The # type: ignore[attr-defined] comment confirms this attribute doesn't exist.

The type: ignore suppresses the type checker but does not prevent the runtime AttributeError. PyGithub's PaginatedList only exposes totalCount (camelCase), not total_count.

Apply this diff:

-                gh_repositories_count = gh_repositories.total_count  # type: ignore[attr-defined]
+                gh_repositories_count = gh_repositories.totalCount
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
gh_repositories_count = gh_repositories.total_count # type: ignore[attr-defined]
gh_repositories_count = gh_repositories.totalCount
🤖 Prompt for AI Agents
In backend/apps/github/management/commands/github_update_owasp_organization.py
around line 70, replace the incorrect use of gh_repositories.total_count (which
doesn't exist at runtime) with the correct PyGithub attribute
gh_repositories.totalCount; remove the `# type: ignore[attr-defined]` and
optionally add a safe fallback (e.g., use getattr(gh_repositories, "totalCount",
0) or wrap access in try/except AttributeError) so the code won't raise at
runtime if the attribute is missing.

Comment on lines +19 to +20
self.total_count = len(items) #for linting errors
self.totalCount = len(items) #for PyGithub compatibility
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Dual-attribute approach in mocks doesn't fix the production runtime errors.

While this mock provides both total_count (line 19) and totalCount (line 20), the production code still accesses .total_count on real PyGithub PaginatedList objects, which only expose totalCount. This makes tests pass but production will fail.

The correct solution: Production code should use totalCount (with linting suppressions), and mocks should only provide totalCount to match PyGithub's actual behavior.

Apply this diff to match PyGithub's API:

     def __init__(self, items):
         self._items = items
-        self.total_count = len(items) #for linting errors
-        self.totalCount = len(items) #for PyGithub compatibility
+        self.totalCount = len(items)  # PyGithub's PaginatedList attribute name
🤖 Prompt for AI Agents
In backend/tests/apps/github/management/commands/github_sync_user_test.py around
lines 19-20, the mock incorrectly defines both total_count and totalCount;
update the mock to only expose totalCount (remove the total_count attribute) so
it matches PyGithub's PaginatedList, and update production code to consistently
access .totalCount (add a lint suppression comment where needed) so runtime
behavior aligns with the real API.

Comment on lines 108 to 120
class PaginatedListMock(list):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.totalCount = len(self)
self.total_count = len(self)

def __getitem__(self, index):
if isinstance(index, slice):
result = super().__getitem__(index)
new_list = PaginatedListMock(result)
new_list.totalCount = self.totalCount
new_list.total_count = self.total_count
return new_list
return super().__getitem__(index)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

PaginatedListMock should use totalCount to match PyGithub's API.

The mock class uses total_count, but PyGithub's actual PaginatedList provides totalCount (camelCase). This creates inconsistency between tests and production behavior.

Apply this diff to all occurrences:

         class PaginatedListMock(list):
             def __init__(self, *args, **kwargs):
                 super().__init__(*args, **kwargs)
-                self.total_count = len(self)
+                self.totalCount = len(self)

             def __getitem__(self, index):
                 if isinstance(index, slice):
                     result = super().__getitem__(index)
                     new_list = PaginatedListMock(result)
-                    new_list.total_count = self.total_count
+                    new_list.totalCount = self.totalCount
                     return new_list
                 return super().__getitem__(index)

And update line 218:

-    mock_repos.total_count = 3
+    mock_repos.totalCount = 3

Also applies to: 198-210, 218-218

🤖 Prompt for AI Agents
In
backend/tests/apps/github/management/commands/github_update_owasp_organization_test.py
around lines 108-120 (also apply same change at 198-210 and update line 218),
the PaginatedListMock uses total_count but PyGithub uses camelCase totalCount;
change the attribute name and any references from total_count to totalCount,
ensure the __init__ sets self.totalCount = len(self), and when slicing create
the new PaginatedListMock and copy self.totalCount to new_list.totalCount, and
update line 218 to reference totalCount as well so the mock matches PyGithub
behavior.

gh_org = mock.Mock()
gh_repos = mock.MagicMock()
gh_repos.totalCount = num_repos
gh_repos.total_count = num_repos
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Test mock should use totalCount to match PyGithub's API.

PyGithub's PaginatedList exposes totalCount (camelCase), not total_count. The mock should match the actual library interface.

Apply this diff:

-    gh_repos.total_count = num_repos
+    gh_repos.totalCount = num_repos
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
gh_repos.total_count = num_repos
gh_repos.totalCount = num_repos
🤖 Prompt for AI Agents
In
backend/tests/apps/github/management/commands/github_update_related_organizations_test.py
around line 53, the test mock sets gh_repos.total_count but PyGithub's
PaginatedList uses totalCount (camelCase); change the mock to set
gh_repos.totalCount = num_repos (and remove or stop using total_count) so the
test matches the actual PyGithub interface and behavior.

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anirudhprmar Please address all CodeRabbit comments

@anirudhprmar
Copy link
Contributor Author

@anirudhprmar Please address all CodeRabbit comments

yeah, on it

@anirudhprmar
Copy link
Contributor Author

@kasya, the changes coderabbit suggests revert back to the original implementation, which makes this entire issue irrelevant. Also i noticed that changing totalCount to total_count is creating more problems and errors. This time i even tried to implement use getattr(commits, 'totalCount', 0) but this still fails the make check-tests

I don't think this issue is a good fix.
Would really appreciate some feedback on this one.

@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rename this field "totalCount" to match the regular expression ^[_a-z][_a-z0-9]*$

2 participants