-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add update repository mutation (#573)
- Loading branch information
1 parent
a3a3716
commit 56dbd5d
Showing
10 changed files
with
242 additions
and
0 deletions.
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
core/commands/repository/interactors/tests/test_update_repository.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import pytest | ||
from asgiref.sync import async_to_sync | ||
from django.contrib.auth.models import AnonymousUser | ||
from django.test import TransactionTestCase | ||
|
||
from codecov.commands.exceptions import Unauthorized | ||
from codecov_auth.tests.factories import OwnerFactory | ||
from core.tests.factories import RepositoryFactory, RepositoryTokenFactory | ||
|
||
from ..update_repository import UpdateRepositoryInteractor | ||
|
||
|
||
class UpdateRepositoryInteractorTest(TransactionTestCase): | ||
def setUp(self): | ||
self.owner = OwnerFactory(username="codecov") | ||
self.random_user = OwnerFactory(organizations=[]) | ||
|
||
def execute_unauthorized_owner(self): | ||
return UpdateRepositoryInteractor(self.owner, "github").execute( | ||
repo_name="repo-1", | ||
owner=self.random_user, | ||
default_branch=None, | ||
activated=None, | ||
) | ||
|
||
async def test_when_validation_error_unauthorized_owner(self): | ||
with pytest.raises(Unauthorized): | ||
await self.execute_unauthorized_owner() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from typing import Optional | ||
|
||
from django.conf import settings | ||
|
||
import services.self_hosted as self_hosted | ||
from codecov.commands.base import BaseInteractor | ||
from codecov.commands.exceptions import Unauthenticated, Unauthorized, ValidationError | ||
from codecov.db import sync_to_async | ||
from codecov_auth.helpers import current_user_part_of_org | ||
from codecov_auth.models import Owner | ||
from core.models import Repository | ||
|
||
|
||
class UpdateRepositoryInteractor(BaseInteractor): | ||
def validate_owner(self, owner: Owner): | ||
if not self.current_user.is_authenticated: | ||
raise Unauthenticated() | ||
|
||
if not current_user_part_of_org(self.current_owner, owner): | ||
raise Unauthorized() | ||
|
||
@sync_to_async | ||
def execute( | ||
self, | ||
repo_name: str, | ||
owner: Owner, | ||
default_branch: Optional[str], | ||
activated: Optional[bool], | ||
): | ||
self.validate_owner(owner) | ||
repo = Repository.objects.filter(author_id=owner.pk, name=repo_name).first() | ||
if not repo: | ||
raise ValidationError("Repo not found") | ||
|
||
if default_branch: | ||
branch = repo.branches.filter(name=default_branch).first() | ||
if branch is None: | ||
raise ValidationError( | ||
f"The branch '{default_branch}' is not in our records. Please provide a valid branch name.", | ||
) | ||
|
||
repo.branch = default_branch | ||
if activated: | ||
repo.activated = activated | ||
repo.save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
from django.test import TransactionTestCase, override_settings | ||
|
||
from codecov_auth.tests.factories import OwnerFactory | ||
from core.tests.factories import BranchFactory, RepositoryFactory | ||
from graphql_api.tests.helper import GraphQLTestHelper | ||
|
||
query = """ | ||
mutation($input: UpdateRepositoryInput!) { | ||
updateRepository(input: $input) { | ||
error { | ||
__typename | ||
... on ResolverError { | ||
message | ||
} | ||
} | ||
} | ||
} | ||
""" | ||
|
||
repo_query = """{ | ||
me { | ||
owner { | ||
repository(name: "gazebo") { | ||
... on Repository { | ||
activated | ||
defaultBranch | ||
} | ||
} | ||
} | ||
} | ||
} | ||
""" | ||
|
||
|
||
class UpdateRepositoryTests(GraphQLTestHelper, TransactionTestCase): | ||
def setUp(self): | ||
self.org = OwnerFactory(username="codecov", service="github") | ||
self.repo = RepositoryFactory(author=self.org, name="gazebo", activated=False) | ||
|
||
def test_when_authenticated_update_activated(self): | ||
data = self.gql_request( | ||
query, | ||
owner=self.org, | ||
variables={"input": {"activated": True, "repoName": "gazebo"}}, | ||
) | ||
|
||
repo_result = self.gql_request( | ||
repo_query, | ||
owner=self.org, | ||
) | ||
assert repo_result["me"]["owner"]["repository"]["activated"] == True | ||
|
||
assert data == {"updateRepository": None} | ||
|
||
def test_when_authenticated_update_branch(self): | ||
other_branch = BranchFactory.create( | ||
name="some other branch", repository=self.repo | ||
) | ||
data = self.gql_request( | ||
query, | ||
owner=self.org, | ||
variables={"input": {"branch": "some other branch", "repoName": "gazebo"}}, | ||
) | ||
|
||
repo_result = self.gql_request( | ||
repo_query, | ||
owner=self.org, | ||
) | ||
assert ( | ||
repo_result["me"]["owner"]["repository"]["defaultBranch"] | ||
== "some other branch" | ||
) | ||
|
||
assert data == {"updateRepository": None} | ||
|
||
def test_when_authenticated_branch_does_not_exist(self): | ||
data = self.gql_request( | ||
query, | ||
owner=self.org, | ||
variables={"input": {"branch": "Dne", "repoName": "gazebo"}}, | ||
) | ||
|
||
assert data["updateRepository"]["error"]["__typename"] == "ValidationError" | ||
|
||
def test_when_unauthenticated(self): | ||
data = self.gql_request( | ||
query, | ||
variables={ | ||
"input": { | ||
"repoName": "gazebo", | ||
} | ||
}, | ||
) | ||
assert data["updateRepository"]["error"]["__typename"] == "UnauthenticatedError" | ||
|
||
def test_when_validation_error_repo_not_found(self): | ||
data = self.gql_request( | ||
query, | ||
owner=self.org, | ||
variables={ | ||
"input": { | ||
"repoName": "DNE", | ||
} | ||
}, | ||
) | ||
assert data["updateRepository"]["error"]["__typename"] == "ValidationError" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from graphql_api.helpers.ariadne import ariadne_load_local_graphql | ||
|
||
from .update_repository import error_update_repository, resolve_update_repository | ||
|
||
gql_update_repository = ariadne_load_local_graphql( | ||
__file__, "update_repository.graphql" | ||
) |
11 changes: 11 additions & 0 deletions
11
graphql_api/types/mutation/update_repository/update_repository.graphql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
union UpdateRepositoryError = UnauthenticatedError | ValidationError | UnauthorizedError | ||
|
||
type UpdateRepositoryPayload { | ||
error: UpdateRepositoryError | ||
} | ||
|
||
input UpdateRepositoryInput { | ||
branch: String | ||
activated: Boolean | ||
repoName: String! | ||
} |
25 changes: 25 additions & 0 deletions
25
graphql_api/types/mutation/update_repository/update_repository.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from ariadne import UnionType | ||
|
||
from graphql_api.helpers.mutation import ( | ||
resolve_union_error_type, | ||
wrap_error_handling_mutation, | ||
) | ||
|
||
|
||
@wrap_error_handling_mutation | ||
async def resolve_update_repository(_, info, input): | ||
command = info.context["executor"].get_command("repository") | ||
owner = info.context["request"].current_owner | ||
repo_name = input.get("repoName") | ||
default_branch = input.get("branch") | ||
activated = input.get("activated") | ||
await command.update_repository( | ||
repo_name, | ||
owner, | ||
default_branch, | ||
activated, | ||
) | ||
|
||
|
||
error_update_repository = UnionType("UpdateRepositoryError") | ||
error_update_repository.type_resolver(resolve_union_error_type) |