From 5616ce8a4b6843facc9d8e15ca234e9069f07a7e Mon Sep 17 00:00:00 2001 From: Moiz Zulfiqar Date: Sun, 25 Jan 2026 05:36:54 +0500 Subject: [PATCH 1/5] Fix docstring formatting per ruff checks --- .../apps/github/models/mixins/repository.py | 138 ++++++++++++-- backend/apps/github/models/mixins/user.py | 170 ++++++++++++++--- backend/apps/owasp/models/project.py | 175 +++++++++++++++--- 3 files changed, 416 insertions(+), 67 deletions(-) diff --git a/backend/apps/github/models/mixins/repository.py b/backend/apps/github/models/mixins/repository.py index 6bd7b27b6c..63767cd05a 100644 --- a/backend/apps/github/models/mixins/repository.py +++ b/backend/apps/github/models/mixins/repository.py @@ -14,7 +14,15 @@ class RepositoryIndexMixin: @property def is_indexable(self) -> bool: - """Repositories to index.""" + """Determine if the repository should be indexed. + + Returns True if the repository is not archived, not empty, not a template, + and is associated with at least one project. + + Returns: + bool: True if repository meets all indexing criteria, False otherwise. + + """ return ( not self.is_archived and not self.is_empty @@ -24,90 +32,182 @@ def is_indexable(self) -> bool: @property def idx_commits_count(self) -> int: - """Return commits count for indexing.""" + """Get the total number of commits in this repository for indexing. + + Returns: + int: The total commit count of the repository. + + """ return self.commits_count @property def idx_contributors_count(self) -> int: - """Return contributors count for indexing.""" + """Get the total number of contributors to this repository for indexing. + + Returns: + int: The total number of unique contributors. + + """ return self.contributors_count @property def idx_created_at(self) -> float: - """Return created at for indexing.""" + """Get the repository creation timestamp for indexing. + + Returns: + float: Unix timestamp (seconds since epoch) when the repository was created. + + """ return self.created_at.timestamp() @property def idx_description(self) -> str: - """Return description for indexing.""" + """Get the repository description for indexing. + + Returns: + str: The repository's description text. + + """ return self.description @property def idx_forks_count(self) -> int: - """Return forks count for indexing.""" + """Get the total number of repository forks for indexing. + + Returns: + int: The total number of times this repository has been forked. + + """ return self.forks_count @property def idx_has_funding_yml(self) -> bool: - """Return has funding.yml for indexing.""" + """Check if the repository has a FUNDING.yml file for indexing. + + Returns: + bool: True if the repository contains a FUNDING.yml file, False otherwise. + + """ return self.has_funding_yml @property def idx_key(self) -> str: - """Return key for indexing.""" + """Get the unique Nest key identifier for this repository for indexing. + + Returns: + str: The repository's unique Nest key. + + """ return self.nest_key @property def idx_languages(self) -> list[str]: - """Return languages for indexing.""" + """Get the programming languages used in this repository for indexing. + + Returns: + list[str]: A list of programming language names detected in the repository. + + """ return self.languages @property def idx_license(self) -> str: - """Return license for indexing.""" + """Get the repository's license identifier for indexing. + + Returns: + str: The SPDX license identifier or name, if available. + + """ return self.license @property def idx_name(self) -> str: - """Return name for indexing.""" + """Get the repository name for indexing. + + Returns: + str: The name of the repository. + + """ return self.name @property def idx_open_issues_count(self) -> int: - """Return open issues count for indexing.""" + """Get the total number of open issues in this repository for indexing. + + Returns: + int: The count of currently open issues and pull requests. + + """ return self.open_issues_count @property def idx_project_key(self) -> str: - """Return project key for indexing.""" + """Get the Nest key of the associated project for indexing. + + Returns: + str: The unique Nest key of the project this repository belongs to, + or an empty string if no project is associated. + + """ return self.project.nest_key if self.project else "" @property def idx_pushed_at(self) -> float: - """Return pushed at for indexing.""" + """Get the timestamp of the last push to this repository for indexing. + + Returns: + float: Unix timestamp (seconds since epoch) of the most recent push. + + """ return self.pushed_at.timestamp() @property def idx_size(self) -> int: - """Return size for indexing.""" + """Get the repository size in kilobytes for indexing. + + Returns: + int: The repository size in KB. + + """ return self.size @property def idx_stars_count(self) -> int: - """Return stars count for indexing.""" + """Get the total number of stars (likes) this repository has received for indexing. + + Returns: + int: The total count of stars/favorites on the repository. + + """ return self.stars_count @property def idx_subscribers_count(self) -> int: - """Return subscribers count for indexing.""" + """Get the total number of watchers/subscribers for this repository for indexing. + + Returns: + int: The count of users watching this repository. + + """ return self.stars_count @property def idx_top_contributors(self) -> list[dict[str, Any]]: - """Return top contributors for indexing.""" + """Get the list of top contributors to this repository for indexing. + + Returns: + list[dict[str, Any]]: A list of dictionaries containing information about + the top contributors to this repository. + + """ return RepositoryContributor.get_top_contributors(repository=self.key) @property def idx_topics(self): - """Return topics for indexing.""" + """Get the topics/tags associated with this repository for indexing. + + Returns: + list: A list of topic tags that categorize this repository. + + """ return self.topics diff --git a/backend/apps/github/models/mixins/user.py b/backend/apps/github/models/mixins/user.py index bdbb2c2f19..a8f1902744 100644 --- a/backend/apps/github/models/mixins/user.py +++ b/backend/apps/github/models/mixins/user.py @@ -12,7 +12,16 @@ class UserIndexMixin: @property def is_indexable(self): - """Users to index.""" + """Determine if the user should be indexed. + + A user is considered indexable if they are not a bot, their login does not + end with common bot suffixes ("Bot" or "-bot"), and their login is not + present in the non-indexable logins list. + + Returns: + bool: True if the user meets all indexing criteria, False otherwise. + + """ return ( not self.is_bot and not self.login.endswith(("Bot", "-bot")) @@ -21,77 +30,154 @@ def is_indexable(self): @property def idx_avatar_url(self) -> str: - """Return avatar URL for indexing.""" + """Get the user's avatar URL for indexing. + + Returns: + str: The URL of the user's avatar image. + + """ return self.avatar_url @property def idx_badge_count(self) -> int: - """Return badge count for indexing.""" + """Get the number of active badges associated with the user. + + Returns: + int: The count of active user badges. + + """ return self.user_badges.filter(is_active=True).count() @property def idx_bio(self) -> str: - """Return bio for indexing.""" + """Get the user's biography text for indexing. + + Returns: + str: The user's bio, if provided; otherwise an empty string. + + """ return self.bio @property def idx_company(self) -> str: - """Return company for indexing.""" + """Get the user's company affiliation for indexing. + + Returns: + str: The company name associated with the user's profile, if any. + + """ return self.company @property def idx_created_at(self) -> float: - """Return created at timestamp for indexing.""" + """Get the account creation timestamp for indexing. + + Returns: + float: Unix timestamp (seconds since epoch) when the account was created. + + """ return self.created_at.timestamp() @property def idx_email(self) -> str: - """Return email for indexing.""" + """Get the user's email address for indexing. + + Returns: + str: The user's email address, if available. + + """ return self.email @property def idx_key(self) -> str: - """Return key for indexing.""" + """Get the unique key identifier for this user used in indexing. + + Returns: + str: The user's login, used as the unique key. + + """ return self.login @property def idx_followers_count(self) -> int: - """Return followers count for indexing.""" + """Get the number of followers for the user. + + Returns: + int: Total count of users following this user. + + """ return self.followers_count @property def idx_following_count(self) -> int: - """Return following count for indexing.""" + """Get the number of users the user is following. + + Returns: + int: Total count of users this user follows. + + """ return self.following_count @property def idx_location(self) -> str: - """Return location for indexing.""" + """Get the user's location for indexing. + + Returns: + str: The user's self-declared location, if available. + + """ return self.location @property def idx_login(self) -> str: - """Return login for indexing.""" + """Get the user's login for indexing. + + Returns: + str: The user's GitHub login handle. + + """ return self.login @property def idx_name(self) -> str: - """Return name for indexing.""" + """Get the user's display name for indexing. + + Returns: + str: The full name displayed on the user's profile, if provided. + + """ return self.name @property def idx_public_repositories_count(self) -> int: - """Return public repositories count for indexing.""" + """Get the number of public repositories owned by the user. + + Returns: + int: Total count of public repositories owned by the user. + + """ return self.public_repositories_count @property def idx_title(self) -> str: - """Return title for indexing.""" + """Get the user's profile title or headline for indexing. + + Returns: + str: The title or headline associated with the user, if any. + + """ return self.title @property def idx_contributions(self): - """Return contributions for indexing.""" + """Get a summary of the user's top repository contributions for indexing. + + Returns: + list[dict]: A list of contribution summaries, each including counts and + metadata about the contributed repositories (e.g., name, stars, + forks, license, and latest release information). + + """ from apps.github.models.repository_contributor import RepositoryContributor return [ @@ -123,12 +209,23 @@ def idx_contributions(self): @property def idx_contributions_count(self) -> int: - """Return contributions count for indexing.""" + """Get the total number of contributions made by the user. + + Returns: + int: Aggregate contributions count across repositories. + + """ return self.contributions_count @property def idx_issues(self) -> list[dict]: - """Return issues for indexing.""" + """Get recent issues associated with the user for indexing. + + Returns: + list[dict]: A list of issue summaries including timestamps, counts, + identifiers, titles, URLs, and minimal repository metadata. + + """ return [ { "created_at": i.created_at.timestamp(), @@ -149,12 +246,24 @@ def idx_issues(self) -> list[dict]: @property def idx_issues_count(self) -> int: - """Return issues count for indexing.""" + """Get the total number of issues associated with the user. + + Returns: + int: Count of issues linked to the user. + + """ return self.issues.count() @property def idx_releases(self) -> list[dict]: - """Return releases for indexing.""" + """Get recent releases associated with the user for indexing. + + Returns: + list[dict]: A list of release summaries including pre-release flag, + names, published timestamps, tags, URLs, and minimal repository + metadata. + + """ return [ { "is_pre_release": r.is_pre_release, @@ -175,15 +284,30 @@ def idx_releases(self) -> list[dict]: @property def idx_releases_count(self) -> int: - """Return releases count for indexing.""" + """Get the total number of releases associated with the user. + + Returns: + int: Count of releases linked to the user. + + """ return self.releases.count() @property def idx_updated_at(self) -> float: - """Return updated at timestamp for indexing.""" + """Get the last profile update timestamp for indexing. + + Returns: + float: Unix timestamp (seconds since epoch) of the last update. + + """ return self.updated_at.timestamp() @property def idx_url(self) -> str: - """Return GitHub profile URL for indexing.""" + """Get the user's GitHub profile URL for indexing. + + Returns: + str: The URL to the user's GitHub profile page. + + """ return self.url diff --git a/backend/apps/owasp/models/project.py b/backend/apps/owasp/models/project.py index 0a6ecdcafb..5d65eb0c8b 100644 --- a/backend/apps/owasp/models/project.py +++ b/backend/apps/owasp/models/project.py @@ -159,44 +159,84 @@ def __str__(self) -> str: @property def entity_leaders(self) -> list[EntityMember]: - """Return project leaders.""" + """Get the list of project leaders. + + Returns: + list[EntityMember]: Up to the top leaders limited by `MAX_LEADERS_COUNT`. + + """ return super().entity_leaders[:MAX_LEADERS_COUNT] @property def health_score(self) -> float | None: - """Return project health score.""" + """Get the latest computed health score for the project. + + Returns: + float | None: The most recent health score, or None if unavailable. + + """ return self.last_health_metrics.score if self.last_health_metrics else None @property def is_code_type(self) -> bool: - """Indicate whether project has CODE type.""" + """Check if the project's type is CODE. + + Returns: + bool: True if the project type equals `ProjectType.CODE`. + + """ return self.type == ProjectType.CODE @property def is_documentation_type(self) -> bool: - """Indicate whether project has DOCUMENTATION type.""" + """Check if the project's type is DOCUMENTATION. + + Returns: + bool: True if the project type equals `ProjectType.DOCUMENTATION`. + + """ return self.type == ProjectType.DOCUMENTATION @property def is_funding_requirements_compliant(self) -> bool: - """Indicate whether project is compliant with funding requirements.""" + """Check if the project complies with funding requirements. + + Returns: + bool: True if all related repositories are funding-policy compliant. + + """ return not self.repositories.filter(is_funding_policy_compliant=False).exists() @property def is_leader_requirements_compliant(self) -> bool: - """Indicate whether project is compliant with project leaders requirements.""" + """Check if the project satisfies OWASP leader requirements. + + Returns: + bool: True if the project has multiple leaders (more than one). + + """ # https://owasp.org/www-committee-project/#div-practice # Have multiple Project Leaders who are not all employed by the same company. return self.leaders_count > 1 @property def is_tool_type(self) -> bool: - """Indicate whether project has TOOL type.""" + """Check if the project's type is TOOL. + + Returns: + bool: True if the project type equals `ProjectType.TOOL`. + + """ return self.type == ProjectType.TOOL @property def issues(self): - """Return issues.""" + """Get all issues across the project's repositories. + + Returns: + QuerySet[Issue]: A queryset of issues with related entities prefetched. + + """ return ( Issue.objects.filter( repository__in=self.repositories.all(), @@ -215,32 +255,62 @@ def issues(self): @property def issues_count(self) -> int: - """Return count of issues.""" + """Get the total number of issues. + + Returns: + int: Count of issues across the project's repositories. + + """ return self.issues.count() @property def last_health_metrics(self) -> ProjectHealthMetrics | None: - """Return last health metrics for the project.""" + """Get the most recent health metrics for the project. + + Returns: + ProjectHealthMetrics | None: Latest metrics record or None if missing. + + """ return self.health_metrics.order_by("-nest_created_at").first() @property def leaders_count(self) -> int: - """Return the count of leaders.""" + """Get the number of project leaders. + + Returns: + int: Count of leaders derived from `leaders_raw`. + + """ return len(self.leaders_raw) @property def nest_key(self) -> str: - """Get Nest key.""" + """Get the Nest-specific project key. + + Returns: + str: The project key with the "www-project-" prefix removed. + + """ return self.key.replace("www-project-", "") @property def nest_url(self) -> str: - """Get Nest URL for project.""" + """Get the absolute Nest URL for this project. + + Returns: + str: The full Nest URL pointing to the project's page. + + """ return get_absolute_url(f"/projects/{self.nest_key}") @property def open_issues(self): - """Return open issues.""" + """Get all open issues across the project's repositories. + + Returns: + QuerySet[Issue]: A queryset of open issues with repository related data. + + """ return Issue.open_issues.filter( repository__in=self.repositories.all(), ).select_related( @@ -249,17 +319,32 @@ def open_issues(self): @property def open_pull_requests_count(self) -> int: - """Return count of open pull requests.""" + """Get the number of open pull requests. + + Returns: + int: Count of pull requests currently in the "open" state. + + """ return self.pull_requests.filter(state="open").count() @property def owasp_page_last_updated_at(self) -> datetime.datetime | None: - """Return the last updated date of the OWASP page.""" + """Get the last updated timestamp of the project's OWASP page. + + Returns: + datetime.datetime | None: The OWASP page's last update time, or None. + + """ return self.owasp_repository.updated_at if self.owasp_repository else None @property def pull_requests(self): - """Return pull requests.""" + """Get all pull requests across the project's repositories. + + Returns: + QuerySet[PullRequest]: A queryset of pull requests with related data. + + """ return ( PullRequest.objects.filter( repository__in=self.repositories.all(), @@ -278,19 +363,34 @@ def pull_requests(self): @property def pull_requests_count(self) -> int: - """Return count of pull requests.""" + """Get the total number of pull requests. + + Returns: + int: Count of pull requests across the project's repositories. + + """ return self.pull_requests.count() @property def pull_request_last_created_at(self) -> datetime.datetime | None: - """Return last created pull request.""" + """Get the most recent pull request creation timestamp. + + Returns: + datetime.datetime | None: Latest `created_at` timestamp, or None. + + """ return self.pull_requests.aggregate( models.Max("created_at"), )["created_at__max"] @property def published_releases(self): - """Return project releases.""" + """Get published releases across the project's repositories. + + Returns: + QuerySet[Release]: A queryset of non-draft releases with related data. + + """ return Release.objects.filter( is_draft=False, published_at__isnull=False, @@ -303,7 +403,12 @@ def published_releases(self): @property def recent_milestones(self): - """Return recent milestones.""" + """Get milestones across the project's repositories. + + Returns: + QuerySet[Milestone]: A queryset of milestones with related data. + + """ return ( Milestone.objects.filter( repository__in=self.repositories.all(), @@ -319,7 +424,12 @@ def recent_milestones(self): @property def recent_releases_count(self) -> int: - """Return count of recent releases per a specific period.""" + """Get the number of releases published in the last 60 days. + + Returns: + int: Count of releases published within the recent 60-day period. + + """ recent_period = timezone.now() - datetime.timedelta(days=60) return self.published_releases.filter( published_at__gte=recent_period, @@ -327,17 +437,32 @@ def recent_releases_count(self) -> int: @property def repositories_count(self) -> int: - """Return count of repositories.""" + """Get the number of repositories associated with this project. + + Returns: + int: Count of repositories linked to the project. + + """ return self.repositories.count() @property def unanswered_issues_count(self) -> int: - """Return count of unanswered issues.""" + """Get the number of issues with no comments. + + Returns: + int: Count of issues where `comments_count` equals zero. + + """ return self.issues.filter(comments_count=0).count() @property def unassigned_issues_count(self) -> int: - """Return count of unassigned issues.""" + """Get the number of issues with no assignees. + + Returns: + int: Count of issues where no user is assigned. + + """ return self.issues.filter(assignees__isnull=True).count() def deactivate(self) -> None: From 8de227efd5e599b5628647053285aad3c038a2c1 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sun, 25 Jan 2026 18:51:01 -0800 Subject: [PATCH 2/5] Update code --- .../apps/github/models/mixins/repository.py | 23 ++++++++----------- backend/apps/github/models/mixins/user.py | 8 ++----- backend/apps/owasp/models/project.py | 10 ++++---- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/backend/apps/github/models/mixins/repository.py b/backend/apps/github/models/mixins/repository.py index 63767cd05a..e6bb22a114 100644 --- a/backend/apps/github/models/mixins/repository.py +++ b/backend/apps/github/models/mixins/repository.py @@ -16,9 +16,6 @@ class RepositoryIndexMixin: def is_indexable(self) -> bool: """Determine if the repository should be indexed. - Returns True if the repository is not archived, not empty, not a template, - and is associated with at least one project. - Returns: bool: True if repository meets all indexing criteria, False otherwise. @@ -55,7 +52,7 @@ def idx_created_at(self) -> float: """Get the repository creation timestamp for indexing. Returns: - float: Unix timestamp (seconds since epoch) when the repository was created. + float: Unix timestamp when the repository was created. """ return self.created_at.timestamp() @@ -115,7 +112,7 @@ def idx_license(self) -> str: """Get the repository's license identifier for indexing. Returns: - str: The SPDX license identifier or name, if available. + str: The license identifier. """ return self.license @@ -135,7 +132,7 @@ def idx_open_issues_count(self) -> int: """Get the total number of open issues in this repository for indexing. Returns: - int: The count of currently open issues and pull requests. + int: The count of currently open issues. """ return self.open_issues_count @@ -156,7 +153,7 @@ def idx_pushed_at(self) -> float: """Get the timestamp of the last push to this repository for indexing. Returns: - float: Unix timestamp (seconds since epoch) of the most recent push. + float: Unix timestamp of the most recent push. """ return self.pushed_at.timestamp() @@ -173,23 +170,23 @@ def idx_size(self) -> int: @property def idx_stars_count(self) -> int: - """Get the total number of stars (likes) this repository has received for indexing. + """Get the total number of stars this repository has received for indexing. Returns: - int: The total count of stars/favorites on the repository. + int: The total count of stars on the repository. """ return self.stars_count @property def idx_subscribers_count(self) -> int: - """Get the total number of watchers/subscribers for this repository for indexing. + """Get the total number of subscribers for this repository for indexing. Returns: int: The count of users watching this repository. """ - return self.stars_count + return self.subscribers_count @property def idx_top_contributors(self) -> list[dict[str, Any]]: @@ -204,10 +201,10 @@ def idx_top_contributors(self) -> list[dict[str, Any]]: @property def idx_topics(self): - """Get the topics/tags associated with this repository for indexing. + """Get the topics associated with this repository for indexing. Returns: - list: A list of topic tags that categorize this repository. + list: A list of topics that categorize this repository. """ return self.topics diff --git a/backend/apps/github/models/mixins/user.py b/backend/apps/github/models/mixins/user.py index a8f1902744..f8f6859ee9 100644 --- a/backend/apps/github/models/mixins/user.py +++ b/backend/apps/github/models/mixins/user.py @@ -14,10 +14,6 @@ class UserIndexMixin: def is_indexable(self): """Determine if the user should be indexed. - A user is considered indexable if they are not a bot, their login does not - end with common bot suffixes ("Bot" or "-bot"), and their login is not - present in the non-indexable logins list. - Returns: bool: True if the user meets all indexing criteria, False otherwise. @@ -73,7 +69,7 @@ def idx_created_at(self) -> float: """Get the account creation timestamp for indexing. Returns: - float: Unix timestamp (seconds since epoch) when the account was created. + float: Unix timestamp when the account was created. """ return self.created_at.timestamp() @@ -256,7 +252,7 @@ def idx_issues_count(self) -> int: @property def idx_releases(self) -> list[dict]: - """Get recent releases associated with the user for indexing. + """Get releases associated with the user for indexing. Returns: list[dict]: A list of release summaries including pre-release flag, diff --git a/backend/apps/owasp/models/project.py b/backend/apps/owasp/models/project.py index 5d65eb0c8b..f278378d3d 100644 --- a/backend/apps/owasp/models/project.py +++ b/backend/apps/owasp/models/project.py @@ -231,7 +231,7 @@ def is_tool_type(self) -> bool: @property def issues(self): - """Get all issues across the project's repositories. + """Get issues across the project's repositories. Returns: QuerySet[Issue]: A queryset of issues with related entities prefetched. @@ -305,7 +305,7 @@ def nest_url(self) -> str: @property def open_issues(self): - """Get all open issues across the project's repositories. + """Get open issues across the project's repositories. Returns: QuerySet[Issue]: A queryset of open issues with repository related data. @@ -339,7 +339,7 @@ def owasp_page_last_updated_at(self) -> datetime.datetime | None: @property def pull_requests(self): - """Get all pull requests across the project's repositories. + """Get pull requests across the project's repositories. Returns: QuerySet[PullRequest]: A queryset of pull requests with related data. @@ -424,10 +424,10 @@ def recent_milestones(self): @property def recent_releases_count(self) -> int: - """Get the number of releases published in the last 60 days. + """Get the number of recent releases. Returns: - int: Count of releases published within the recent 60-day period. + int: Count of releases published recently. """ recent_period = timezone.now() - datetime.timedelta(days=60) From 6ebc0f372adc1007cd83031361555fff63006fde Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sun, 25 Jan 2026 18:58:33 -0800 Subject: [PATCH 3/5] Update code --- backend/apps/github/models/mixins/repository.py | 2 +- backend/apps/github/models/mixins/user.py | 2 +- backend/apps/owasp/models/project.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/apps/github/models/mixins/repository.py b/backend/apps/github/models/mixins/repository.py index e6bb22a114..5586d1e9c0 100644 --- a/backend/apps/github/models/mixins/repository.py +++ b/backend/apps/github/models/mixins/repository.py @@ -200,7 +200,7 @@ def idx_top_contributors(self) -> list[dict[str, Any]]: return RepositoryContributor.get_top_contributors(repository=self.key) @property - def idx_topics(self): + def idx_topics(self) -> list[str]: """Get the topics associated with this repository for indexing. Returns: diff --git a/backend/apps/github/models/mixins/user.py b/backend/apps/github/models/mixins/user.py index f8f6859ee9..ed25aedc26 100644 --- a/backend/apps/github/models/mixins/user.py +++ b/backend/apps/github/models/mixins/user.py @@ -159,7 +159,7 @@ def idx_title(self) -> str: """Get the user's profile title or headline for indexing. Returns: - str: The title or headline associated with the user, if any. + str: The title or headline associated with the user. """ return self.title diff --git a/backend/apps/owasp/models/project.py b/backend/apps/owasp/models/project.py index f278378d3d..37305845b7 100644 --- a/backend/apps/owasp/models/project.py +++ b/backend/apps/owasp/models/project.py @@ -384,7 +384,7 @@ def pull_request_last_created_at(self) -> datetime.datetime | None: )["created_at__max"] @property - def published_releases(self): + def published_releases(self) -> models.QuerySet[Release]: """Get published releases across the project's repositories. Returns: @@ -402,7 +402,7 @@ def published_releases(self): ) @property - def recent_milestones(self): + def recent_milestones(self) -> models.QuerySet[Milestone]: """Get milestones across the project's repositories. Returns: From 89fa86691eac678a8ffe47f98d07e30cc535f1c3 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sun, 25 Jan 2026 19:07:23 -0800 Subject: [PATCH 4/5] Update code --- .../github/models/mixins/repository_test.py | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/backend/tests/apps/github/models/mixins/repository_test.py b/backend/tests/apps/github/models/mixins/repository_test.py index ef83099886..b77f742c68 100644 --- a/backend/tests/apps/github/models/mixins/repository_test.py +++ b/backend/tests/apps/github/models/mixins/repository_test.py @@ -9,27 +9,29 @@ FORKS_COUNT = 5 OPEN_ISSUES_COUNT = 5 STARS_COUNT = 5 +SUBSCRIBERS_COUNT = 10 @pytest.fixture def repository_index_mixin_instance(): instance = RepositoryIndexMixin() + instance.commits_count = 100 instance.contributors_count = CONTRIBUTORS_COUNT + instance.created_at = datetime(2020, 1, 1, tzinfo=UTC) instance.description = "Description" instance.forks_count = FORKS_COUNT + instance.has_funding_yml = True instance.languages = ["Python", "JavaScript"] + instance.license = "MIT" instance.name = "Name" + instance.nest_key = "nest/key" instance.open_issues_count = OPEN_ISSUES_COUNT + instance.project = None instance.pushed_at = datetime(2021, 1, 1, tzinfo=UTC) + instance.size = 1024 instance.stars_count = STARS_COUNT + instance.subscribers_count = SUBSCRIBERS_COUNT instance.topics = ["Topic1", "Topic2"] - instance.created_at = datetime(2020, 1, 1, tzinfo=UTC) - instance.size = 1024 - instance.has_funding_yml = True - instance.license = "MIT" - instance.project = None - instance.commits_count = 100 - instance.nest_key = "nest/key" return instance @@ -104,22 +106,22 @@ def test_idx_top_contributors(self, repository_index_mixin_instance, mocker): @pytest.mark.parametrize( ("attr", "expected"), [ + ("idx_commits_count", 100), ("idx_contributors_count", CONTRIBUTORS_COUNT), + ("idx_created_at", datetime(2020, 1, 1, tzinfo=UTC).timestamp()), ("idx_description", "Description"), ("idx_forks_count", FORKS_COUNT), + ("idx_has_funding_yml", True), + ("idx_key", "nest/key"), ("idx_languages", ["Python", "JavaScript"]), + ("idx_license", "MIT"), ("idx_name", "Name"), ("idx_open_issues_count", OPEN_ISSUES_COUNT), ("idx_pushed_at", datetime(2021, 1, 1, tzinfo=UTC).timestamp()), + ("idx_size", 1024), ("idx_stars_count", STARS_COUNT), + ("idx_subscribers_count", SUBSCRIBERS_COUNT), ("idx_topics", ["Topic1", "Topic2"]), - ("idx_created_at", datetime(2020, 1, 1, tzinfo=UTC).timestamp()), - ("idx_has_funding_yml", True), - ("idx_license", "MIT"), - ("idx_subscribers_count", STARS_COUNT), - ("idx_commits_count", 100), - ("idx_size", 1024), - ("idx_key", "nest/key"), ], ) def test_repository_index(self, repository_index_mixin_instance, attr, expected): From f53de9dcc7e8131e8c3670d78752ababf3011b22 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sun, 25 Jan 2026 19:12:35 -0800 Subject: [PATCH 5/5] Update tests --- backend/tests/apps/github/models/mixins/repository_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/tests/apps/github/models/mixins/repository_test.py b/backend/tests/apps/github/models/mixins/repository_test.py index b77f742c68..65cb79a672 100644 --- a/backend/tests/apps/github/models/mixins/repository_test.py +++ b/backend/tests/apps/github/models/mixins/repository_test.py @@ -5,9 +5,11 @@ from apps.github.models.mixins.repository import RepositoryIndexMixin from apps.github.models.release import Release +COMMITS_COUNT = 100 CONTRIBUTORS_COUNT = 5 FORKS_COUNT = 5 OPEN_ISSUES_COUNT = 5 +REPOSITORY_SIZE = 1024 STARS_COUNT = 5 SUBSCRIBERS_COUNT = 10 @@ -15,7 +17,7 @@ @pytest.fixture def repository_index_mixin_instance(): instance = RepositoryIndexMixin() - instance.commits_count = 100 + instance.commits_count = COMMITS_COUNT instance.contributors_count = CONTRIBUTORS_COUNT instance.created_at = datetime(2020, 1, 1, tzinfo=UTC) instance.description = "Description" @@ -28,7 +30,7 @@ def repository_index_mixin_instance(): instance.open_issues_count = OPEN_ISSUES_COUNT instance.project = None instance.pushed_at = datetime(2021, 1, 1, tzinfo=UTC) - instance.size = 1024 + instance.size = REPOSITORY_SIZE instance.stars_count = STARS_COUNT instance.subscribers_count = SUBSCRIBERS_COUNT instance.topics = ["Topic1", "Topic2"]