Skip to content

Commit

Permalink
Merge branch 'main' into Improve-NestBot-/users-command
Browse files Browse the repository at this point in the history
  • Loading branch information
Naveen-Pal authored Feb 6, 2025
2 parents 94a55ce + 777d712 commit 4c450c7
Show file tree
Hide file tree
Showing 28 changed files with 1,810 additions and 970 deletions.
46 changes: 42 additions & 4 deletions backend/apps/github/graphql/nodes/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,63 @@
import graphene

from apps.common.graphql.nodes import BaseNode
from apps.github.graphql.nodes.issue import IssueNode
from apps.github.graphql.nodes.release import ReleaseNode
from apps.github.graphql.nodes.repository_contributor import RepositoryContributorNode
from apps.github.models.repository import Repository

RECENT_ISSUES_LIMIT = 10
RECENT_RELEASES_LIMIT = 10


class RepositoryNode(BaseNode):
"""GitHub repository node."""
"""Repository node."""

issues = graphene.List(IssueNode)
languages = graphene.List(graphene.String)
releases = graphene.List(ReleaseNode)
top_contributors = graphene.List(RepositoryContributorNode)
topics = graphene.List(graphene.String)
url = graphene.String()

class Meta:
model = Repository
fields = (
"name",
"commits_count",
"contributors_count",
"created_at",
"description",
"forks_count",
"stars_count",
"key",
"license",
"name",
"open_issues_count",
"size",
"stars_count",
"subscribers_count",
"contributors_count",
"updated_at",
)

def resolve_issues(self, info):
"""Resolve recent issues."""
return self.issues.select_related("author").order_by("-created_at")[:RECENT_ISSUES_LIMIT]

def resolve_languages(self, info):
"""Resolve languages."""
return self.languages.keys()

def resolve_releases(self, info):
"""Resolve recent releases."""
return self.published_releases.order_by("-published_at")[:RECENT_RELEASES_LIMIT]

def resolve_top_contributors(self, info):
"""Resolve top contributors."""
return self.idx_top_contributors

def resolve_topics(self, info):
"""Resolve topics."""
return self.topics

def resolve_url(self, info):
"""Resolve URL."""
return self.url
12 changes: 12 additions & 0 deletions backend/apps/github/graphql/nodes/repository_contributor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""GitHub repository GraphQL node."""

import graphene


class RepositoryContributorNode(graphene.ObjectType):
"""Repository contributor node."""

avatar_url = graphene.String()
contributions_count = graphene.Int()
login = graphene.String()
name = graphene.String()
7 changes: 7 additions & 0 deletions backend/apps/github/graphql/queries/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""GitHub GraphQL queries."""

from apps.github.graphql.queries.repository import RepositoryQuery


class GithubQuery(RepositoryQuery):
"""GitHub query."""
28 changes: 28 additions & 0 deletions backend/apps/github/graphql/queries/repository.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""OWASP project GraphQL queries."""

import graphene

from apps.common.graphql.queries import BaseQuery
from apps.github.graphql.nodes.repository import RepositoryNode
from apps.owasp.models.project import Project


class RepositoryQuery(BaseQuery):
"""Repository queries."""

repository = graphene.Field(
RepositoryNode,
project_key=graphene.String(required=True),
repository_key=graphene.String(required=True),
)

def resolve_repository(root, info, project_key, repository_key):
"""Resolve project."""
try:
return (
Project.objects.get(key=project_key)
.repositories.filter(key=repository_key)
.first()
)
except Project.DoesNotExist:
return None
7 changes: 5 additions & 2 deletions backend/apps/owasp/graphql/queries/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
class ProjectQuery(BaseQuery):
"""Project queries."""

project = graphene.Field(ProjectNode, key=graphene.String(required=True))
project = graphene.Field(
ProjectNode,
key=graphene.String(required=True),
)

def resolve_project(root, info, key):
"""Resolve project by key."""
"""Resolve project."""
try:
return Project.objects.get(key=key)
except Project.DoesNotExist:
Expand Down
297 changes: 101 additions & 196 deletions backend/poetry.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion backend/settings/graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import graphene

from apps.github.graphql.queries import GithubQuery
from apps.owasp.graphql.queries import OwaspQuery


class Query(OwaspQuery):
class Query(GithubQuery, OwaspQuery):
"""Schema queries."""


Expand Down
52 changes: 44 additions & 8 deletions backend/tests/github/graphql/nodes/repository_test.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,69 @@
"""Test cases for RepositoryNode."""

from graphene import List

from apps.common.graphql.nodes import BaseNode
from apps.github.graphql.nodes.issue import IssueNode
from apps.github.graphql.nodes.release import ReleaseNode
from apps.github.graphql.nodes.repository import RepositoryNode
from apps.github.models.repository import Repository


class TestRepositoryNode:
"""Test cases for RepositoryNode class."""

def test_repository_node_inheritance(self):
"""Test if RepositoryNode inherits from BaseNode."""
assert issubclass(RepositoryNode, BaseNode)

def test_meta_configuration(self):
"""Test if Meta is properly configured."""
assert RepositoryNode._meta.model == Repository
expected_fields = {
"commits_count",
"contributors_count",
"created_at",
"description",
"forks_count",
"issues",
"key",
"languages",
"license",
"name",
"open_issues_count",
"releases",
"size",
"stars_count",
"subscribers_count",
"top_contributors",
"topics",
"updated_at",
"url",
}
assert set(RepositoryNode._meta.fields) == expected_fields

def test_resolve_url_field(self, mocker):
"""Test if URL field is properly defined."""
field = RepositoryNode._meta.fields.get("url")
def test_resolve_languages(self, mocker):
field = RepositoryNode._meta.fields.get("languages")
assert field is not None
assert str(field.type) == "[String]"

def test_resolve_topics(self, mocker):
field = RepositoryNode._meta.fields.get("topics")
assert field is not None
assert str(field.type) == "[String]"

def test_resolve_issues(self, mocker):
field = RepositoryNode._meta.fields.get("issues")
assert field is not None
assert str(field.type) == "String"
assert field.type == List(IssueNode)

def test_resolve_releases(self, mocker):
field = RepositoryNode._meta.fields.get("releases")
assert field is not None
assert field.type == List(ReleaseNode)

def test_resolve_top_contributors(self, mocker):
field = RepositoryNode._meta.fields.get("top_contributors")
assert field is not None
assert str(field.type) == "[RepositoryContributorNode]"

def test_resolve_url(self, mocker):
url = RepositoryNode._meta.fields.get("url")
assert url is not None
assert str(url.type) == "String"
Empty file.
65 changes: 65 additions & 0 deletions backend/tests/github/graphql/queries/repository_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""Test cases for RepositoryQuery."""

from unittest.mock import Mock, patch

import pytest

from apps.github.graphql.queries.repository import RepositoryQuery
from apps.owasp.models.project import Project


class TestRepositoryQuery:
"""Test cases for RepositoryQuery class."""

@pytest.fixture()
def mock_info(self):
"""GraphQL info mock fixture."""
return Mock()

@pytest.fixture()
def mock_project(self):
"""Project mock fixture."""
return Mock(spec=Project)

def test_resolve_repository_existing(self, mock_project, mock_info):
"""Test resolving an existing repository."""
mock_repository = Mock()
mock_project.repositories.filter.return_value.first.return_value = mock_repository

with patch("apps.owasp.models.project.Project.objects.get") as mock_get:
mock_get.return_value = mock_project

result = RepositoryQuery.resolve_repository(
None, mock_info, project_key="test-project", repository_key="test-repo"
)

assert result == mock_repository
mock_get.assert_called_once_with(key="test-project")
mock_project.repositories.filter.assert_called_once_with(key="test-repo")

def test_resolve_repository_not_found_project(self, mock_info):
"""Test resolving a non-existent project."""
with patch("apps.owasp.models.project.Project.objects.get") as mock_get:
mock_get.side_effect = Project.DoesNotExist

result = RepositoryQuery.resolve_repository(
None, mock_info, project_key="non-existent-project", repository_key="test-repo"
)

assert result is None
mock_get.assert_called_once_with(key="non-existent-project")

def test_resolve_repository_not_found_repository(self, mock_project, mock_info):
"""Test resolving a non-existent repository in an existing project."""
mock_project.repositories.filter.return_value.first.return_value = None

with patch("apps.owasp.models.project.Project.objects.get") as mock_get:
mock_get.return_value = mock_project

result = RepositoryQuery.resolve_repository(
None, mock_info, project_key="test-project", repository_key="non-existent-repo"
)

assert result is None
mock_get.assert_called_once_with(key="test-project")
mock_project.repositories.filter.assert_called_once_with(key="non-existent-repo")
3 changes: 3 additions & 0 deletions frontend/__tests__/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ jest.mock('pages', () => ({
ChapterDetailsPage: () => <div data-testid="chapter-details-page">ChapterDetailsPage Page</div>,
CommitteeDetailsPage: () => <div data-testid="committee-details-page">CommitteeDetails Page</div>,
ProjectDetailsPage: () => <div data-testid="project-details-page">ProjectDetails Page</div>,
RepositoryDetailsPage: () => (
<div data-testid="repository-details-page">RepositoryDetails Page</div>
),
UserDetailsPage: () => <div data-testid="user-details-page">UserDetails Page</div>,
UsersPage: () => <div data-testid="users-page">Users Page</div>,
}))
Expand Down
49 changes: 49 additions & 0 deletions frontend/__tests__/src/data/mockRepositoryData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export const mockRepositoryData = {
repository: {
name: 'Test Repo',
updatedAt: '2024-01-01T00:00:00Z',
license: 'MIT',
size: 1200,
url: 'https://github.com/test-repo',
commitsCount: 10,
contributorsCount: 5,
forksCount: 3,
openIssuesCount: 2,
starsCount: 50,
topContributors: Array.from({ length: 15 }, (_, i) => ({
avatarUrl: `https://example.com/avatar${i + 1}.jpg`,
contributionsCount: 30 - i,
login: `contributor${i + 1}`,
name: `Contributor ${i + 1}`,
})),
languages: ['JavaScript', 'TypeScript'],
topics: ['web', 'security'],
description: 'A sample test repository',
createdAt: '2023-12-15T00:00:00Z',
issues: [
{
title: 'Bug fix required',
commentsCount: 4,
createdAt: '2024-01-02T10:00:00Z',
author: {
avatarUrl: 'https://example.com/avatar.jpg',
name: 'Test User 1',
login: 'user1',
},
},
],
releases: [
{
name: 'v1.0.0',
tagName: 'v1.0.0',
isPreRelease: false,
publishedAt: '2024-01-01T12:00:00Z',
author: {
avatarUrl: 'https://example.com/avatar.jpg',
name: 'Test User 2',
login: 'user2',
},
},
],
},
}
Loading

0 comments on commit 4c450c7

Please sign in to comment.