diff --git a/README.md b/README.md
index 426bd6f..1b95752 100644
--- a/README.md
+++ b/README.md
@@ -66,9 +66,9 @@ print(users)
created_merge_request = client.create_merge_request(project_id=123, source_branch="development",
target_branch="production",title="Merge Request Title")
-print(created_merge_request)
-
-print(f"Users: {client.get_users()}")
+print(f"Merge Request Title: {created_merge_request.data.title}\nDescription: {created_merge_request.data.description}")
+users = client.get_users()
+print(f"First user's email: {users.data[0].email}")
print(f"Projects: {client.get_projects()}")
diff --git a/gitlab_api/gitlab_api.py b/gitlab_api/gitlab_api.py
index a70dd4d..d129432 100644
--- a/gitlab_api/gitlab_api.py
+++ b/gitlab_api/gitlab_api.py
@@ -6,7 +6,7 @@
from requests import Response
import urllib3
from base64 import b64encode
-from typing import List, Dict
+from typing import Union
from pydantic import ValidationError
try:
@@ -65,6 +65,10 @@
ParameterError,
MissingParameterError,
)
+try:
+ from gitlab_api.utils import process_response
+except ModuleNotFoundError:
+ from utils import process_response
class Api(object):
@@ -118,7 +122,7 @@ def __init__(
# Branches API #
####################################################################################################################
@require_auth
- def get_branches(self, **kwargs) -> Response:
+ def get_branches(self, **kwargs) -> Union[Response, requests.Response]:
"""
Retrieve information about branches in a project.
@@ -141,10 +145,11 @@ def get_branches(self, **kwargs) -> Response:
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_branch(self, **kwargs) -> Response:
+ def get_branch(self, **kwargs) -> Union[Response, requests.Response]:
"""
Retrieve information about a specific branch in a project.
@@ -166,10 +171,11 @@ def get_branch(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_branch(self, **kwargs) -> Response:
+ def create_branch(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a new branch in a project.
@@ -191,10 +197,11 @@ def create_branch(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_branch(self, **kwargs) -> Response:
+ def delete_branch(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a specific branch in a project.
@@ -217,10 +224,11 @@ def delete_branch(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_merged_branches(self, **kwargs) -> Response:
+ def delete_merged_branches(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete merged branches in a project.
@@ -243,13 +251,14 @@ def delete_merged_branches(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Commits API #
####################################################################################################################
@require_auth
- def get_commits(self, **kwargs) -> Response:
+ def get_commits(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get commits.
@@ -271,10 +280,11 @@ def get_commits(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit(self, **kwargs) -> Response:
+ def get_commit(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get a specific commit.
@@ -297,10 +307,11 @@ def get_commit(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit_references(self, **kwargs) -> Response:
+ def get_commit_references(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get references of a commit.
@@ -323,10 +334,11 @@ def get_commit_references(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def cherry_pick_commit(self, **kwargs) -> Response:
+ def cherry_pick_commit(self, **kwargs) -> Union[Response, requests.Response]:
"""
Cherry-pick a commit into a new branch.
@@ -345,15 +357,16 @@ def cherry_pick_commit(self, **kwargs) -> Response:
url=f"{self.url}/projects/{commit.project_id}"
f"/repository/commits/{commit.commit_hash}/cherry_pick",
headers=self.headers,
- data=json.dumps(commit.data, indent=2),
+ json=commit.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_commit(self, **kwargs) -> Response:
+ def create_commit(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a new commit.
@@ -371,15 +384,16 @@ def create_commit(self, **kwargs) -> Response:
response = self._session.post(
url=f"{self.url}/projects/{commit.project_id}" f"/repository/commits",
headers=self.headers,
- data=json.dumps(commit.data, indent=2),
+ json=commit.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def revert_commit(self, **kwargs) -> Response:
+ def revert_commit(self, **kwargs) -> Union[Response, requests.Response]:
"""
Revert a commit.
@@ -398,15 +412,16 @@ def revert_commit(self, **kwargs) -> Response:
url=f"{self.url}/projects/{commit.project_id}"
f"/repository/commits/{commit.commit_hash}/revert",
headers=self.headers,
- data=json.dumps(commit.data, indent=2),
+ json=commit.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit_diff(self, **kwargs) -> Response:
+ def get_commit_diff(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get the diff of a commit.
@@ -429,10 +444,11 @@ def get_commit_diff(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit_comments(self, **kwargs) -> Response:
+ def get_commit_comments(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get comments on a commit.
@@ -455,10 +471,11 @@ def get_commit_comments(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_commit_comment(self, **kwargs) -> Response:
+ def create_commit_comment(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a comment on a commit.
@@ -477,15 +494,16 @@ def create_commit_comment(self, **kwargs) -> Response:
url=f"{self.url}/projects/{commit.project_id}"
f"/repository/commits/{commit.commit_hash}/comments",
headers=self.headers,
- data=json.dumps(commit.data, indent=2),
+ json=commit.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit_discussions(self, **kwargs) -> Response:
+ def get_commit_discussions(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get discussions on a commit.
@@ -508,10 +526,11 @@ def get_commit_discussions(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit_statuses(self, **kwargs) -> Response:
+ def get_commit_statuses(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get statuses of a commit.
@@ -534,10 +553,13 @@ def get_commit_statuses(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def post_build_status_to_commit(self, **kwargs) -> Response:
+ def post_build_status_to_commit(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Post build status to a commit.
@@ -556,15 +578,16 @@ def post_build_status_to_commit(self, **kwargs) -> Response:
url=f"{self.url}/projects/{commit.project_id}"
f"/statuses/{commit.commit_hash}/",
headers=self.headers,
- data=json.dumps(commit.data, indent=2),
+ json=commit.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit_merge_requests(self, **kwargs) -> Response:
+ def get_commit_merge_requests(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get merge requests associated with a commit.
@@ -587,10 +610,11 @@ def get_commit_merge_requests(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_commit_gpg_signature(self, **kwargs) -> Response:
+ def get_commit_gpg_signature(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get GPG signature of a commit.
@@ -613,13 +637,14 @@ def get_commit_gpg_signature(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Deploy Tokens API #
####################################################################################################################
@require_auth
- def get_deploy_tokens(self) -> Response:
+ def get_deploy_tokens(self) -> Union[Response, requests.Response]:
"""
Get all deploy tokens.
@@ -638,10 +663,11 @@ def get_deploy_tokens(self) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_deploy_tokens(self, **kwargs) -> Response:
+ def get_project_deploy_tokens(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get deploy tokens for a specific project.
@@ -663,10 +689,11 @@ def get_project_deploy_tokens(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_deploy_token(self, **kwargs) -> Response:
+ def get_project_deploy_token(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get a specific deploy token for a project.
@@ -688,10 +715,13 @@ def get_project_deploy_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_project_deploy_token(self, **kwargs) -> Response:
+ def create_project_deploy_token(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Create a deploy token for a project.
@@ -721,10 +751,13 @@ def create_project_deploy_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_project_deploy_token(self, **kwargs) -> Response:
+ def delete_project_deploy_token(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Delete a deploy token for a project.
@@ -749,10 +782,11 @@ def delete_project_deploy_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_deploy_tokens(self, **kwargs) -> Response:
+ def get_group_deploy_tokens(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get deploy tokens for a specific group.
@@ -777,10 +811,11 @@ def get_group_deploy_tokens(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_deploy_token(self, **kwargs) -> Response:
+ def get_group_deploy_token(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get a specific deploy token for a group.
@@ -806,10 +841,11 @@ def get_group_deploy_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_group_deploy_token(self, **kwargs) -> Response:
+ def create_group_deploy_token(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a deploy token for a group.
@@ -839,10 +875,11 @@ def create_group_deploy_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_group_deploy_token(self, **kwargs) -> Response:
+ def delete_group_deploy_token(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a deploy token for a group.
@@ -867,13 +904,14 @@ def delete_group_deploy_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Groups API #
####################################################################################################################
@require_auth
- def get_groups(self, **kwargs) -> Response:
+ def get_groups(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get a list of groups.
@@ -895,10 +933,11 @@ def get_groups(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group(self, **kwargs) -> Response:
+ def get_group(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get details of a specific group.
@@ -923,10 +962,11 @@ def get_group(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_subgroups(self, **kwargs) -> Response:
+ def get_group_subgroups(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get subgroups of a specific group.
@@ -951,10 +991,13 @@ def get_group_subgroups(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_descendant_groups(self, **kwargs) -> Response:
+ def get_group_descendant_groups(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Get descendant groups of a specific group.
@@ -979,10 +1022,11 @@ def get_group_descendant_groups(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_projects(self, **kwargs) -> Response:
+ def get_group_projects(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get projects associated with a specific group.
@@ -1009,10 +1053,11 @@ def get_group_projects(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_merge_requests(self, **kwargs) -> Response:
+ def get_group_merge_requests(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get merge requests associated with a specific group.
@@ -1039,13 +1084,14 @@ def get_group_merge_requests(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Jobs API #
####################################################################################################################
@require_auth
- def get_project_jobs(self, **kwargs) -> Response:
+ def get_project_jobs(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get jobs associated with a specific project.
@@ -1070,10 +1116,11 @@ def get_project_jobs(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_job(self, **kwargs) -> Response:
+ def get_project_job(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get details of a specific job within a project.
@@ -1099,10 +1146,11 @@ def get_project_job(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_job_log(self, **kwargs) -> Response:
+ def get_project_job_log(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get the log of a specific job within a project.
@@ -1127,10 +1175,11 @@ def get_project_job_log(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def cancel_project_job(self, **kwargs) -> Response:
+ def cancel_project_job(self, **kwargs) -> Union[Response, requests.Response]:
"""
Cancel a specific job within a project.
@@ -1155,10 +1204,11 @@ def cancel_project_job(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def retry_project_job(self, **kwargs) -> Response:
+ def retry_project_job(self, **kwargs) -> Union[Response, requests.Response]:
"""
Retry a specific job within a project.
@@ -1183,10 +1233,11 @@ def retry_project_job(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def erase_project_job(self, **kwargs) -> Response:
+ def erase_project_job(self, **kwargs) -> Union[Response, requests.Response]:
"""
Erase a specific job within a project.
@@ -1211,10 +1262,11 @@ def erase_project_job(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def run_project_job(self, **kwargs) -> Response:
+ def run_project_job(self, **kwargs) -> Union[Response, requests.Response]:
"""
Run a specific job within a project.
@@ -1236,15 +1288,16 @@ def run_project_job(self, **kwargs) -> Response:
response = self._session.post(
url=f"{self.url}/projects/{job.project_id}/jobs/{job.job_id}/play",
headers=self.headers,
- data=json.dumps(job.data, indent=2),
+ json=job.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_pipeline_jobs(self, **kwargs) -> Response:
+ def get_pipeline_jobs(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get jobs associated with a specific pipeline within a project.
@@ -1269,13 +1322,14 @@ def get_pipeline_jobs(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Members API #
####################################################################################################################
@require_auth
- def get_group_members(self, **kwargs) -> Response:
+ def get_group_members(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get members of a specific group.
@@ -1300,10 +1354,11 @@ def get_group_members(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_members(self, **kwargs) -> Response:
+ def get_project_members(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get members of a specific project.
@@ -1328,13 +1383,14 @@ def get_project_members(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Merge Request API #
####################################################################################################################
@require_auth
- def create_merge_request(self, **kwargs) -> Response:
+ def create_merge_request(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a new merge request.
@@ -1361,15 +1417,16 @@ def create_merge_request(self, **kwargs) -> Response:
url=f"{self.url}/projects"
f"/{merge_request.project_id}/merge_requests",
headers=self.headers,
- data=json.dumps(merge_request.data, indent=2),
+ json=merge_request.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_merge_requests(self, **kwargs) -> Response:
+ def get_merge_requests(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get a list of merge requests.
@@ -1406,10 +1463,13 @@ def get_merge_requests(self, **kwargs) -> Response:
response = response + response_page
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_merge_requests(self, **kwargs) -> Response:
+ def get_project_merge_requests(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Get merge requests for a specific project.
@@ -1433,10 +1493,11 @@ def get_project_merge_requests(self, **kwargs) -> Response:
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_merge_request(self, **kwargs) -> Response:
+ def get_project_merge_request(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get details of a specific merge request in a project.
@@ -1462,13 +1523,14 @@ def get_project_merge_request(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Merge Rules API #
####################################################################################################################
@require_auth
- def get_project_level_rules(self, **kwargs) -> Response:
+ def get_project_level_rules(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get project-level merge request approval rules.
@@ -1490,10 +1552,11 @@ def get_project_level_rules(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_level_rule(self, **kwargs) -> Response:
+ def get_project_level_rule(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get details of a specific project-level merge request approval rule.
@@ -1516,10 +1579,11 @@ def get_project_level_rule(self, **kwargs) -> Response:
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_project_level_rule(self, **kwargs) -> Response:
+ def create_project_level_rule(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a new project-level merge request approval rule.
@@ -1537,16 +1601,17 @@ def create_project_level_rule(self, **kwargs) -> Response:
response = self._session.post(
url=f"{self.url}/projects/{merge_rule.project_id}/approval_rules",
headers=self.headers,
- data=json.dumps(merge_rule.data, indent=2),
+ json=merge_rule.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def update_project_level_rule(self, **kwargs) -> Response:
+ def update_project_level_rule(self, **kwargs) -> Union[Response, requests.Response]:
"""
Update an existing project-level merge request approval rule.
@@ -1565,15 +1630,16 @@ def update_project_level_rule(self, **kwargs) -> Response:
url=f"{self.url}/projects/{merge_rule.project_id}"
f"/approval_rules/{merge_rule.approval_rule_id}",
headers=self.headers,
- data=json.dumps(merge_rule.data, indent=2),
+ json=merge_rule.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_project_level_rule(self, **kwargs) -> Response:
+ def delete_project_level_rule(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a project-level merge request approval rule.
@@ -1592,15 +1658,18 @@ def delete_project_level_rule(self, **kwargs) -> Response:
url=f"{self.url}/projects/{merge_rule.project_id}"
f"/approval_rules/{merge_rule.approval_rule_id}",
headers=self.headers,
- data=json.dumps(merge_rule.data, indent=2),
+ json=merge_rule.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def merge_request_level_approvals(self, **kwargs) -> Response:
+ def merge_request_level_approvals(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Get approvals for a specific merge request.
@@ -1619,16 +1688,20 @@ def merge_request_level_approvals(self, **kwargs) -> Response:
raise MissingParameterError
try:
response = self._session.get(
- url=f"{self.url}/projects/{merge_rule.project_id}/merge_requests/{merge_rule.merge_request_iid}/approvals",
+ url=f"{self.url}/projects/{merge_rule.project_id}/merge_requests/"
+ f"{merge_rule.merge_request_iid}/approvals",
headers=self.headers,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_approval_state_merge_requests(self, **kwargs) -> Response:
+ def get_approval_state_merge_requests(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Get the approval state of merge requests for a specific project.
@@ -1654,10 +1727,13 @@ def get_approval_state_merge_requests(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_merge_request_level_rules(self, **kwargs) -> Response:
+ def get_merge_request_level_rules(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Get merge request-level approval rules for a specific project and merge request.
@@ -1683,10 +1759,11 @@ def get_merge_request_level_rules(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def approve_merge_request(self, **kwargs) -> Response:
+ def approve_merge_request(self, **kwargs) -> Union[Response, requests.Response]:
"""
Approve a specific merge request.
@@ -1712,10 +1789,11 @@ def approve_merge_request(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def unapprove_merge_request(self, **kwargs) -> Response:
+ def unapprove_merge_request(self, **kwargs) -> Union[Response, requests.Response]:
"""
Unapprove a specific merge request.
@@ -1741,12 +1819,13 @@ def unapprove_merge_request(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Packages API #
####################################################################################################################
- def get_repository_packages(self, **kwargs) -> Response:
+ def get_repository_packages(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about repository packages for a specific project.
@@ -1771,9 +1850,12 @@ def get_repository_packages(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
- def publish_repository_package(self, **kwargs) -> Response:
+ def publish_repository_package(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Publish a repository package for a specific project.
@@ -1805,9 +1887,12 @@ def publish_repository_package(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
- def download_repository_package(self, **kwargs) -> Response:
+ def download_repository_package(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Download a repository package for a specific project.
@@ -1839,13 +1924,14 @@ def download_repository_package(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Pipeline API #
####################################################################################################################
@require_auth
- def get_pipelines(self, **kwargs) -> Response:
+ def get_pipelines(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about pipelines for a specific project.
@@ -1870,10 +1956,11 @@ def get_pipelines(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_pipeline(self, **kwargs) -> Response:
+ def get_pipeline(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about a specific pipeline in a project.
@@ -1899,10 +1986,11 @@ def get_pipeline(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def run_pipeline(self, **kwargs) -> Response:
+ def run_pipeline(self, **kwargs) -> Union[Response, requests.Response]:
"""
Run a pipeline for a specific project.
@@ -1924,7 +2012,7 @@ def run_pipeline(self, **kwargs) -> Response:
url=f"{self.url}/projects/{pipeline.project_id}"
f"/pipeline{pipeline.api_parameters}",
headers=self.headers,
- data=json.dumps(pipeline.variables, indent=2),
+ json=pipeline.variables,
verify=self.verify,
)
else:
@@ -1934,13 +2022,14 @@ def run_pipeline(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
####################################################################################################################
# Projects API #
####################################################################################################################
@require_auth
- def get_projects(self, **kwargs) -> Response:
+ def get_projects(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about projects.
@@ -1971,10 +2060,11 @@ def get_projects(self, **kwargs) -> Response:
)
response_page = json.loads(response_page.text.replace("'", '"'))
response = response + response_page
+ response = process_response(response=response)
return response
@require_auth
- def get_project(self, **kwargs) -> Response:
+ def get_project(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about a specific project.
@@ -1997,10 +2087,13 @@ def get_project(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def get_nested_projects_by_group(self, **kwargs) -> List[Dict]:
+ def get_nested_projects_by_group(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Get information about nested projects within a group.
@@ -2043,7 +2136,7 @@ def get_nested_projects_by_group(self, **kwargs) -> List[Dict]:
return projects
@require_auth
- def get_project_contributors(self, **kwargs) -> Response:
+ def get_project_contributors(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about contributors to a project.
@@ -2065,10 +2158,11 @@ def get_project_contributors(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def get_project_statistics(self, **kwargs) -> Response:
+ def get_project_statistics(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get statistics for a specific project.
@@ -2090,10 +2184,11 @@ def get_project_statistics(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def edit_project(self, **kwargs) -> Response:
+ def edit_project(self, **kwargs) -> Union[Response, requests.Response]:
"""
Edit a specific project.
@@ -2116,10 +2211,11 @@ def edit_project(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_groups(self, **kwargs) -> Response:
+ def get_project_groups(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get groups associated with a specific project.
@@ -2141,10 +2237,11 @@ def get_project_groups(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def archive_project(self, **kwargs) -> Response:
+ def archive_project(self, **kwargs) -> Union[Response, requests.Response]:
"""
Archive a specific project.
@@ -2166,10 +2263,11 @@ def archive_project(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def unarchive_project(self, **kwargs) -> Response:
+ def unarchive_project(self, **kwargs) -> Union[Response, requests.Response]:
"""
Unarchive a specific project.
@@ -2191,10 +2289,11 @@ def unarchive_project(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def delete_project(self, **kwargs) -> Response:
+ def delete_project(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a specific project.
@@ -2216,10 +2315,11 @@ def delete_project(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def share_project(self, **kwargs) -> Response:
+ def share_project(self, **kwargs) -> Union[Response, requests.Response]:
"""
Share a specific project with a group.
@@ -2246,13 +2346,14 @@ def share_project(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
####################################################################################################################
# Protected Branches API #
####################################################################################################################
@require_auth
- def get_protected_branches(self, **kwargs) -> Response:
+ def get_protected_branches(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about protected branches in a project.
@@ -2273,10 +2374,11 @@ def get_protected_branches(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def get_protected_branch(self, **kwargs) -> Response:
+ def get_protected_branch(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about a specific protected branch in a project.
@@ -2298,10 +2400,11 @@ def get_protected_branch(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def protect_branch(self, **kwargs) -> Response:
+ def protect_branch(self, **kwargs) -> Union[Response, requests.Response]:
"""
Protect a specific branch in a project.
@@ -2323,7 +2426,7 @@ def protect_branch(self, **kwargs) -> Response:
url=f"{self.url}/projects/{protected_branch.project_id}"
f"/protected_branches{protected_branch.api_parameters}",
headers=self.headers,
- data=json.dumps(protected_branch.data, indent=2),
+ json=protected_branch.data,
verify=self.verify,
)
else:
@@ -2333,10 +2436,11 @@ def protect_branch(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def unprotect_branch(self, **kwargs) -> Response:
+ def unprotect_branch(self, **kwargs) -> Union[Response, requests.Response]:
"""
Unprotect a specific branch in a project.
@@ -2355,10 +2459,13 @@ def unprotect_branch(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
@require_auth
- def require_code_owner_approvals_single_branch(self, **kwargs) -> Response:
+ def require_code_owner_approvals_single_branch(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Require code owner approvals for a specific branch in a project.
@@ -2380,13 +2487,14 @@ def require_code_owner_approvals_single_branch(self, **kwargs) -> Response:
headers=self.headers,
verify=self.verify,
)
+ response = process_response(response=response)
return response
####################################################################################################################
# Release API #
####################################################################################################################
@require_auth
- def get_releases(self, **kwargs) -> Response:
+ def get_releases(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about releases in a project.
@@ -2408,10 +2516,11 @@ def get_releases(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_latest_release(self, **kwargs) -> Response:
+ def get_latest_release(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about the latest release in a project.
@@ -2435,10 +2544,13 @@ def get_latest_release(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_latest_release_evidence(self, **kwargs) -> Response:
+ def get_latest_release_evidence(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Get evidence for the latest release in a project.
@@ -2462,10 +2574,11 @@ def get_latest_release_evidence(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_latest_release_asset(self, **kwargs) -> Response:
+ def get_latest_release_asset(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get the asset for the latest release in a project.
@@ -2489,10 +2602,11 @@ def get_latest_release_asset(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_releases(self, **kwargs) -> Response:
+ def get_group_releases(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about releases in a group.
@@ -2515,10 +2629,11 @@ def get_group_releases(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def download_release_asset(self, **kwargs) -> Response:
+ def download_release_asset(self, **kwargs) -> Union[Response, requests.Response]:
"""
Download a release asset from a group's release.
@@ -2543,10 +2658,11 @@ def download_release_asset(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_release_by_tag(self, **kwargs) -> Response:
+ def get_release_by_tag(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about a release by its tag in a project.
@@ -2569,10 +2685,11 @@ def get_release_by_tag(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_release(self, **kwargs) -> Response:
+ def create_release(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a new release in a project.
@@ -2589,16 +2706,17 @@ def create_release(self, **kwargs) -> Response:
try:
response = self._session.post(
url=f"{self.url}" f"/projects/{release.project_id}/releases",
- data=json.dumps(release.data, indent=2),
+ json=release.data,
headers=self.headers,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_release_evidence(self, **kwargs) -> Response:
+ def create_release_evidence(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create evidence for a release in a project.
@@ -2622,10 +2740,11 @@ def create_release_evidence(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def update_release(self, **kwargs) -> Response:
+ def update_release(self, **kwargs) -> Union[Response, requests.Response]:
"""
Update information about a release in a project.
@@ -2643,16 +2762,17 @@ def update_release(self, **kwargs) -> Response:
response = self._session.put(
url=f"{self.url}"
f"/projects/{release.project_id}/releases/{release.tag_name}",
- data=json.dumps(release.data, indent=2),
+ json=release.data,
headers=self.headers,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_release(self, **kwargs) -> Response:
+ def delete_release(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a release in a project.
@@ -2675,13 +2795,14 @@ def delete_release(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Runners API #
####################################################################################################################
@require_auth
- def get_runners(self, **kwargs) -> Response:
+ def get_runners(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about runners.
@@ -2703,10 +2824,11 @@ def get_runners(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_runner(self, **kwargs) -> Response:
+ def get_runner(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about a specific runner.
@@ -2731,10 +2853,11 @@ def get_runner(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def update_runner_details(self, **kwargs) -> Response:
+ def update_runner_details(self, **kwargs) -> Union[Response, requests.Response]:
"""
Update details for a specific runner.
@@ -2755,15 +2878,16 @@ def update_runner_details(self, **kwargs) -> Response:
response = self._session.put(
url=f"{self.url}/runners/{runner.runner_id}",
headers=self.headers,
- data=json.dumps(runner.data, indent=2),
+ json=runner.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def pause_runner(self, **kwargs) -> Response:
+ def pause_runner(self, **kwargs) -> Union[Response, requests.Response]:
"""
Pause or unpause a specific runner.
@@ -2784,15 +2908,16 @@ def pause_runner(self, **kwargs) -> Response:
response = self._session.put(
url=f"{self.url}/runners/{runner.runner_id}",
headers=self.headers,
- data=json.dumps(runner.data, indent=2),
+ json=runner.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_runner_jobs(self, **kwargs) -> Response:
+ def get_runner_jobs(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get jobs for a specific runner.
@@ -2817,10 +2942,11 @@ def get_runner_jobs(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_project_runners(self, **kwargs) -> Response:
+ def get_project_runners(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about runners in a project.
@@ -2846,10 +2972,11 @@ def get_project_runners(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def enable_project_runner(self, **kwargs) -> Response:
+ def enable_project_runner(self, **kwargs) -> Union[Response, requests.Response]:
"""
Enable or disable a runner in a project.
@@ -2871,15 +2998,16 @@ def enable_project_runner(self, **kwargs) -> Response:
response = self._session.put(
url=f"{self.url}/projects" f"/{runner.project_id}/runners",
headers=self.headers,
- data=json.dumps(runner.data, indent=2),
+ json=runner.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_project_runner(self, **kwargs) -> Response:
+ def delete_project_runner(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a runner from a project.
@@ -2905,10 +3033,11 @@ def delete_project_runner(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_group_runners(self, **kwargs) -> Response:
+ def get_group_runners(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about runners in a group.
@@ -2934,10 +3063,11 @@ def get_group_runners(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def register_new_runner(self, **kwargs) -> Response:
+ def register_new_runner(self, **kwargs) -> Union[Response, requests.Response]:
"""
Register a new runner.
@@ -2958,15 +3088,16 @@ def register_new_runner(self, **kwargs) -> Response:
response = self._session.put(
url=f"{self.url}/runners",
headers=self.headers,
- data=json.dumps(runner.data, indent=2),
+ json=runner.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_runner(self, **kwargs) -> Response:
+ def delete_runner(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a runner.
@@ -2994,15 +3125,18 @@ def delete_runner(self, **kwargs) -> Response:
response = self._session.delete(
url=f"{self.url}/runners",
headers=self.headers,
- data=json.dumps(runner.data, indent=2),
+ json=runner.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def verify_runner_authentication(self, **kwargs) -> Response:
+ def verify_runner_authentication(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Verify runner authentication.
@@ -3023,15 +3157,16 @@ def verify_runner_authentication(self, **kwargs) -> Response:
response = self._session.post(
url=f"{self.url}/runners/verify",
headers=self.headers,
- data=json.dumps(runner.data, indent=2),
+ json=runner.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def reset_gitlab_runner_token(self) -> Response:
+ def reset_gitlab_runner_token(self) -> Union[Response, requests.Response]:
"""
Reset GitLab runner registration token.
@@ -3049,10 +3184,13 @@ def reset_gitlab_runner_token(self) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def reset_project_runner_token(self, **kwargs) -> Response:
+ def reset_project_runner_token(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Reset registration token for a project's runner.
@@ -3079,10 +3217,11 @@ def reset_project_runner_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def reset_group_runner_token(self, **kwargs) -> Response:
+ def reset_group_runner_token(self, **kwargs) -> Union[Response, requests.Response]:
"""
Reset registration token for a group's runner.
@@ -3108,10 +3247,11 @@ def reset_group_runner_token(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def reset_token(self, **kwargs) -> Response:
+ def reset_token(self, **kwargs) -> Union[Response, requests.Response]:
"""
Reset authentication token for a runner.
@@ -3133,18 +3273,19 @@ def reset_token(self, **kwargs) -> Response:
url=f"{self.url}/runners/{runner.runner_id}"
f"/reset_authentication_token",
headers=self.headers,
- data=json.dumps(runner.data, indent=2),
+ json=runner.data,
verify=self.verify,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Users API #
####################################################################################################################
@require_auth
- def get_users(self, **kwargs) -> Response:
+ def get_users(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about users.
@@ -3177,10 +3318,11 @@ def get_users(self, **kwargs) -> Response:
)
response_page = json.loads(response_page.text.replace("'", '"'))
response = response + response_page
+ response = process_response(response=response)
return response
@require_auth
- def get_user(self, **kwargs) -> Response:
+ def get_user(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about a specific user.
@@ -3205,13 +3347,14 @@ def get_user(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
####################################################################################################################
# Wiki API #
####################################################################################################################
@require_auth
- def get_wiki_list(self, **kwargs) -> Response:
+ def get_wiki_list(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get a list of wiki pages for a project.
@@ -3237,10 +3380,11 @@ def get_wiki_list(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def get_wiki_page(self, **kwargs) -> Response:
+ def get_wiki_page(self, **kwargs) -> Union[Response, requests.Response]:
"""
Get information about a specific wiki page.
@@ -3266,10 +3410,11 @@ def get_wiki_page(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def create_wiki_page(self, **kwargs) -> Response:
+ def create_wiki_page(self, **kwargs) -> Union[Response, requests.Response]:
"""
Create a new wiki page for a project.
@@ -3291,14 +3436,15 @@ def create_wiki_page(self, **kwargs) -> Response:
url=f"{self.url}/projects/{wiki.project_id}/wikis",
headers=self.headers,
verify=self.verify,
- data=json.dumps(wiki.data, indent=2),
+ json=wiki.data,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def update_wiki_page(self, **kwargs) -> Response:
+ def update_wiki_page(self, **kwargs) -> Union[Response, requests.Response]:
"""
Update an existing wiki page for a project.
@@ -3320,14 +3466,15 @@ def update_wiki_page(self, **kwargs) -> Response:
url=f"{self.url}/projects/{wiki.project_id}/wikis/{wiki.slug}",
headers=self.headers,
verify=self.verify,
- data=json.dumps(wiki.data, indent=2),
+ json=wiki.data,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def delete_wiki_page(self, **kwargs) -> Response:
+ def delete_wiki_page(self, **kwargs) -> Union[Response, requests.Response]:
"""
Delete a wiki page for a project.
@@ -3352,10 +3499,13 @@ def delete_wiki_page(self, **kwargs) -> Response:
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
@require_auth
- def upload_wiki_page_attachment(self, **kwargs) -> Response:
+ def upload_wiki_page_attachment(
+ self, **kwargs
+ ) -> Union[Response, requests.Response]:
"""
Upload an attachment to a wiki page for a project.
@@ -3372,12 +3522,6 @@ def upload_wiki_page_attachment(self, **kwargs) -> Response:
wiki = WikiModel(**kwargs)
if wiki.project_id is None or wiki.file is None or wiki.branch is None:
raise MissingParameterError
- data = {}
- if wiki.file:
- if not isinstance(wiki.file, str):
- raise ParameterError
- data["file"] = f"@{wiki.file}"
- data = json.dumps(data, indent=4)
headers = self.headers
headers["Content-Type"] = "multipart/form-data"
try:
@@ -3385,8 +3529,9 @@ def upload_wiki_page_attachment(self, **kwargs) -> Response:
url=f"{self.url}/projects/{wiki.project_id}/wikis/attachments",
headers=headers,
verify=self.verify,
- data=json.dumps(data, indent=2),
+ json=wiki.data,
)
except ValidationError as e:
raise ParameterError(f"Invalid parameters: {e.errors()}")
+ response = process_response(response=response)
return response
diff --git a/gitlab_api/gitlab_models.py b/gitlab_api/gitlab_models.py
index f4d8b37..f78741d 100644
--- a/gitlab_api/gitlab_models.py
+++ b/gitlab_api/gitlab_models.py
@@ -1,7 +1,20 @@
-from typing import Union, List, Dict, Optional
-from pydantic import BaseModel, field_validator, model_validator
+#!/usr/bin/python
+# coding: utf-8
+import logging
import re
+from typing import Union, List, Dict, Optional, Any
+from pydantic import (
+ BaseModel,
+ Field,
+ ConfigDict,
+ field_validator,
+ model_validator,
+ HttpUrl,
+ EmailStr,
+)
+from datetime import datetime
+
try:
from gitlab_api.decorators import require_auth
except ModuleNotFoundError:
@@ -19,6 +32,14 @@
MissingParameterError,
)
+logging.basicConfig(
+ level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s"
+)
+
+########################################################################################################################
+# Input Models #
+########################################################################################################################
+
class BranchModel(BaseModel):
"""
@@ -30,7 +51,7 @@ class BranchModel(BaseModel):
reference (str, optional): Reference information for the branch.
api_parameters (str): Additional API parameters for the group.
- Notes:
+ Comments:
This model includes a validator `validate_required_parameters` to ensure that the `project_id` field is
provided when either `branch` or `reference` is specified.
"""
@@ -117,7 +138,7 @@ class CommitModel(BaseModel):
reference: Optional[str] = None
name: Optional[str] = None
context: Optional[str] = None
- target_url: Optional[str] = None
+ target_url: Optional[Union[HttpUrl, str]] = None
description: Optional[str] = None
coverage: Optional[Union[float, str]] = None
pipeline_id: Optional[Union[int, str]] = None
@@ -125,7 +146,7 @@ class CommitModel(BaseModel):
start_branch: Optional[str] = None
start_sha: Optional[str] = None
start_project: Optional[Union[int, str]] = None
- author_email: Optional[str] = None
+ author_email: Optional[EmailStr] = None
author_name: Optional[str] = None
stats: Optional[bool] = None
force: Optional[bool] = None
@@ -362,7 +383,8 @@ def construct_data_dict(cls, values):
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@@ -1001,7 +1023,8 @@ def build_api_parameters(cls, values):
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@field_validator("scope")
@@ -1343,7 +1366,8 @@ def construct_data_dict(cls, values):
# Remove None values
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@@ -1541,7 +1565,7 @@ class ProjectModel(BaseModel):
- analytics_access_level (str): Access level for analytics.
- approvals_before_merge (int): Number of approvals required before merge.
- auto_cancel_pending_pipelines (str): Auto-cancel pending pipelines.
- - ... (other attributes)
+ - default=None (other attributes)
Methods:
- build_api_parameters(values): Build API parameters.
@@ -1585,7 +1609,7 @@ class ProjectModel(BaseModel):
expires_at: Optional[str] = None
forking_access_level: Optional[str] = None
group_access: Optional[int] = None
- import_url: Optional[str] = None
+ import_url: Optional[Union[HttpUrl, str]] = None
issues_access_level: Optional[str] = None
issues_template: Optional[str] = None
keep_latest_artifact: Optional[bool] = None
@@ -1873,7 +1897,8 @@ def build_api_parameters(cls, values):
# Remove None values
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@@ -2109,7 +2134,8 @@ def build_api_parameters(cls, values):
# Remove None values
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@field_validator("allow_force_push", "code_owner_approval_required")
@@ -2272,7 +2298,8 @@ def build_api_parameters(cls, values):
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@@ -2464,7 +2491,8 @@ def build_api_parameters(cls, values):
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@@ -2786,10 +2814,13 @@ def build_api_parameters(cls, values):
data["title"] = values.get("title")
if "format" in values:
data["format"] = values.get("format")
+ if "file" in values:
+ data["file"] = f'@{values.get("file")}'
data = {k: v for k, v in data.items() if v is not None}
- values["data"] = data
+ if "data" not in values or values["data"] is None:
+ values["data"] = data
return values
@@ -2828,3 +2859,3103 @@ def validate_project_id_type(cls, value):
if not isinstance(value, (int, str)):
raise ValueError("Project ID must be an integer or a string")
return value
+
+
+########################################################################################################################
+# Output Models #
+########################################################################################################################
+class IssueStats(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="IssueStats")
+ total: Optional[int] = Field(default=None, description="Total number of issues")
+ closed: Optional[int] = Field(default=None, description="Number of closed issues")
+ opened: Optional[int] = Field(default=None, description="Number of opened issues")
+
+
+class Milestone(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Milestone")
+ id: Optional[int] = Field(
+ default=None, description="Unique identifier for the milestone"
+ )
+ iid: Optional[int] = Field(
+ default=None, description="Internal ID for the milestone"
+ )
+ project_id: Optional[int] = Field(
+ default=None, description="ID of the project the milestone belongs to"
+ )
+ title: Optional[str] = Field(default=None, description="Title of the milestone")
+ description: Optional[str] = Field(
+ default=None, description="Description of the milestone"
+ )
+ state: Optional[str] = Field(
+ default=None, description="State of the milestone (e.g., active, closed)"
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the milestone was created"
+ )
+ updated_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the milestone was last updated"
+ )
+ due_date: Optional[str] = Field(
+ default=None, description="Due date for the milestone"
+ )
+ start_date: Optional[str] = Field(
+ default=None, description="Start date for the milestone"
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL to the milestone in GitLab"
+ )
+ closed_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the milestone was closed."
+ )
+ issue_stats: Optional[IssueStats] = Field(
+ default=None, description="Statistics of issues related to the milestone"
+ )
+
+
+class TimeStats(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="TimeStats")
+ time_estimate: Optional[int] = Field(
+ default=None,
+ description="Estimated time to complete the merge request (in seconds)",
+ )
+ total_time_spent: Optional[int] = Field(
+ default=None, description="Total time spent on the merge request (in seconds)"
+ )
+ human_time_estimate: Optional[str] = Field(
+ default=None,
+ description="Human-readable estimated time to complete the merge request",
+ )
+ human_total_time_spent: Optional[str] = Field(
+ default=None, description="Human-readable total time spent on the merge request"
+ )
+
+
+class TaskCompletionStatus(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="TaskCompletionStatus")
+ count: Optional[int] = Field(
+ default=None, description="Total number of tasks in the merge request"
+ )
+ completed_count: Optional[int] = Field(
+ default=None, description="Number of completed tasks in the merge request"
+ )
+
+
+class References(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="References")
+ short: Optional[str] = Field(
+ default=None, description="Short reference of the merge request"
+ )
+ relative: Optional[str] = Field(
+ default=None, description="Relative reference of the merge request"
+ )
+ full: Optional[str] = Field(
+ default=None, description="Full reference of the merge request"
+ )
+
+
+class Artifact(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Artifact")
+ file_type: Optional[str] = Field(
+ default=None, description="Type of the artifact file."
+ )
+ size: Optional[int] = Field(default=None, description="Size of the artifact file.")
+ filename: Optional[str] = Field(
+ default=None, description="Filename of the artifact file."
+ )
+ file_format: Optional[str] = Field(
+ default=None, description="Format of the artifact file."
+ )
+
+
+class ArtifactsFile(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ArtifactsFile")
+ filename: Optional[str] = Field(
+ default=None, description="Filename of the artifacts file."
+ )
+ size: Optional[int] = Field(default=None, description="Size of the artifacts file.")
+
+
+class RunnerManager(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="RunnerManager")
+ id: Optional[int] = Field(default=None, description="ID of the runner manager.")
+ system_id: Optional[str] = Field(
+ default=None, description="System ID of the runner manager."
+ )
+ version: Optional[str] = Field(
+ default=None, description="Version of the runner manager."
+ )
+ revision: Optional[str] = Field(
+ default=None, description="Revision of the runner manager."
+ )
+ platform: Optional[str] = Field(
+ default=None, description="Platform of the runner manager."
+ )
+ architecture: Optional[str] = Field(
+ default=None, description="Architecture of the runner manager."
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the runner manager was created."
+ )
+ contacted_at: Optional[datetime] = Field(
+ default=None,
+ description="Timestamp when the runner manager was last contacted.",
+ )
+ ip_address: Optional[str] = Field(
+ default=None, description="IP address of the runner manager."
+ )
+ status: Optional[str] = Field(
+ default=None, description="Status of the runner manager."
+ )
+
+
+class Configuration(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Configuration")
+ approvals_before_merge: Optional[int] = Field(
+ default=None, description="Number of approvals required before merge"
+ )
+ reset_approvals_on_push: Optional[bool] = Field(
+ default=None, description="Whether approvals reset on new push"
+ )
+ selective_code_owner_removals: Optional[bool] = Field(
+ default=None, description="Whether selective code owner removals are allowed"
+ )
+ disable_overriding_approvers_per_merge_request: Optional[bool] = Field(
+ default=None,
+ description="Whether overriding approvers per merge request is disabled",
+ )
+ merge_requests_author_approval: Optional[bool] = Field(
+ default=None, description="Whether authors can approve their own merge requests"
+ )
+ merge_requests_disable_committers_approval: Optional[bool] = Field(
+ default=None, description="Whether committers are disabled from approving"
+ )
+ require_password_to_approve: Optional[bool] = Field(
+ default=None, description="Whether a password is required to approve"
+ )
+
+
+class Iteration(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Iteration")
+ id: Optional[int] = Field(default=None)
+ iid: Optional[int] = Field(default=None)
+ sequence: Optional[int] = Field(default=None)
+ group_id: Optional[int] = Field(default=None)
+ title: Optional[str] = Field(default=None)
+ description: Optional[str] = Field(default=None)
+ state: Optional[int] = Field(default=None)
+ created_at: Optional[datetime] = Field(default=None)
+ updated_at: Optional[datetime] = Field(default=None)
+ start_date: Optional[str] = Field(default=None)
+ due_date: Optional[str] = Field(default=None)
+ web_url: Optional[Union[HttpUrl, str]] = Field(default=None)
+
+
+class Identity(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Identity")
+ provider: Optional[str] = Field(default=None, description="The external provider.")
+ extern_uid: Optional[str] = Field(
+ default=None, description="The external authentication provider UID."
+ )
+
+
+class GroupSamlIdentity(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="GroupSamlIdentity")
+ extern_uid: Optional[str] = Field(
+ default=None, description="External UID of the SAML identity"
+ )
+ provider: Optional[str] = Field(
+ default=None, description="Provider of the SAML identity"
+ )
+ saml_provider_id: Optional[int] = Field(
+ default=None, description="ID of the SAML provider"
+ )
+
+
+class CreatedBy(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="CreatedBy")
+ id: Optional[int] = Field(
+ default=None, description="ID of the user who created the member"
+ )
+ username: Optional[str] = Field(
+ default=None, description="Username of the user who created the member"
+ )
+ name: Optional[str] = Field(
+ default=None, description="Name of the user who created the member"
+ )
+ state: Optional[str] = Field(
+ default=None, description="State of the user who created the member"
+ )
+ avatar_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="Avatar URL of the user who created the member"
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="Web URL of the user who created the member"
+ )
+
+
+class User(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="User")
+ id: Optional[int] = Field(default=None, description="The unique ID of the user.")
+ username: Optional[str] = Field(
+ default=None, description="The username of the user."
+ )
+ user: Optional[str] = Field(default=None, description="The user.")
+ email: Optional[EmailStr] = Field(
+ default=None, description="The email of the user."
+ )
+ name: Optional[str] = Field(default=None, description="The name of the user.")
+ state: Optional[str] = Field(
+ default=None, description="The state of the user (e.g., active, blocked)."
+ )
+ locked: Optional[bool] = Field(
+ default=None, description="Indicates if the user is locked."
+ )
+ avatar_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The URL of the user's avatar."
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The URL of the user's web profile."
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="The creation date of the user."
+ )
+ is_admin: Optional[bool] = Field(
+ default=None, description="Indicates if the user is an administrator."
+ )
+ bio: Optional[str] = Field(default=None, description="The bio of the user.")
+ location: Optional[str] = Field(
+ default=None, description="The location of the user."
+ )
+ skype: Optional[str] = Field(default=None, description="The Skype ID of the user.")
+ linkedin: Optional[str] = Field(
+ default=None, description="The LinkedIn ID of the user."
+ )
+ twitter: Optional[str] = Field(
+ default=None, description="The Twitter handle of the user."
+ )
+ discord: Optional[str] = Field(
+ default=None, description="The Discord ID of the user."
+ )
+ website_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The website URL of the user."
+ )
+ organization: Optional[str] = Field(
+ default=None, description="The organization the user belongs to."
+ )
+ job_title: Optional[str] = Field(
+ default=None, description="The job title of the user."
+ )
+ last_sign_in_at: Optional[datetime] = Field(
+ default=None, description="The last sign-in date of the user."
+ )
+ confirmed_at: Optional[datetime] = Field(
+ default=None, description="The date the user was confirmed."
+ )
+ theme_id: Optional[int] = Field(
+ default=None, description="The theme ID of the user's profile."
+ )
+ last_activity_on: Optional[datetime] = Field(
+ default=None, description="The last activity date of the user."
+ )
+ color_scheme_id: Optional[int] = Field(
+ default=None, description="The color scheme ID of the user's profile."
+ )
+ projects_limit: Optional[int] = Field(
+ default=None, description="The project limit for the user."
+ )
+ current_sign_in_at: Optional[datetime] = Field(
+ default=None, description="The current sign-in date of the user."
+ )
+ note: Optional[str] = Field(default=None, description="A note about the user.")
+ identities: Optional[List[Identity]] = Field(
+ default=None,
+ description="List of external identities associated with the user.",
+ )
+ can_create_group: Optional[bool] = Field(
+ default=None, description="Indicates if the user can create groups."
+ )
+ can_create_project: Optional[bool] = Field(
+ default=None, description="Indicates if the user can create projects."
+ )
+ two_factor_enabled: Optional[bool] = Field(
+ default=None, description="Indicates if two-factor authentication is enabled."
+ )
+ external: Optional[bool] = Field(
+ default=None, description="Indicates if the user is external."
+ )
+ private_profile: Optional[bool] = Field(
+ default=None, description="Indicates if the user's profile is private."
+ )
+ current_sign_in_ip: Optional[str] = Field(
+ default=None, description="The current sign-in IP of the user."
+ )
+ last_sign_in_ip: Optional[str] = Field(
+ default=None, description="The last sign-in IP of the user."
+ )
+ namespace_id: Optional[int] = Field(
+ default=None, description="The namespace ID of the user."
+ )
+ created_by: Optional[Union[int, CreatedBy]] = Field(
+ default=None, description="The ID of the user who created this user."
+ )
+ email_reset_offered_at: Optional[datetime] = Field(
+ default=None, description="The date when an email reset was offered."
+ )
+ expires_at: Optional[datetime] = Field(
+ default=None, description="Timestamp of when the member's access expires"
+ )
+ access_level: Optional[int] = Field(
+ default=None, description="Access level of the member"
+ )
+ group_saml_identity: Optional[GroupSamlIdentity] = Field(
+ default=None, description="SAML identity details of the member"
+ )
+ approved: Optional[bool] = Field(
+ default=None, description="Approval status of the pending member"
+ )
+ invited: Optional[bool] = Field(
+ default=None, description="Invitation status of the pending member"
+ )
+ public_email: Optional[str] = Field(
+ None, description="Public email address of the user"
+ )
+ pronouns: Optional[str] = Field(None, description="Pronouns of the user")
+ bot: Optional[bool] = Field(
+ default=None, description="Indicates if the user is a bot"
+ )
+ work_information: Optional[str] = Field(
+ None, description="Work information of the user"
+ )
+ followers: Optional[int] = Field(
+ default=None, description="Number of followers the user has"
+ )
+ following: Optional[int] = Field(
+ default=None, description="Number of people the user is following"
+ )
+ local_time: Optional[str] = Field(None, description="Local time of the user")
+ commit_email: Optional[str] = Field(
+ default=None, description="Commit email address of the user"
+ )
+ shared_runners_minutes_limit: Optional[int] = Field(
+ None, description="Shared runners minutes limit for the user"
+ )
+ extra_shared_runners_minutes_limit: Optional[int] = Field(
+ None, description="Extra shared runners minutes limit"
+ )
+ membership_type: Optional[str] = Field(None, description="Membership type")
+ removable: Optional[bool] = Field(
+ default=None, description="Whether or not the members are removable"
+ )
+ last_login_at: Optional[datetime] = Field(
+ default=None, description="The last login-in date of the user."
+ )
+
+
+class Users(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Users")
+ users: List[User] = Field(default=None, description="All the users")
+
+
+class Namespace(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Namespace")
+ id: Optional[int] = Field(default=None, description="The ID of the namespace.")
+ name: Optional[str] = Field(default=None, description="The name of the namespace.")
+ path: Optional[str] = Field(default=None, description="The path of the namespace.")
+ kind: Optional[str] = Field(default=None, description="The kind of the namespace.")
+ full_path: Optional[str] = Field(
+ default=None, description="The full path of the namespace."
+ )
+ parent_id: Optional[int] = Field(
+ default=None, description="The parent ID of the namespace, if any."
+ )
+ avatar_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The avatar URL of the namespace."
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The web URL of the namespace."
+ )
+
+
+class ContainerExpirationPolicy(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ContainerExpirationPolicy")
+ cadence: Optional[str] = Field(
+ default=None, description="The cadence of the expiration policy."
+ )
+ enabled: Optional[bool] = Field(
+ default=None, description="Whether the expiration policy is enabled."
+ )
+ keep_n: Optional[int] = Field(default=None, description="Number of items to keep.")
+ older_than: Optional[str] = Field(
+ default=None, description="Items older than this will be removed."
+ )
+ name_regex: Optional[str] = Field(default=None, description="Regex to match names.")
+ name_regex_keep: Optional[str] = Field(
+ default=None, description="Regex to match names to keep."
+ )
+ next_run_at: Optional[datetime] = Field(
+ default=None, description="The next run time of the policy."
+ )
+
+
+class Permissions(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Permissions")
+ project_access: Optional[Dict] = Field(
+ default=None, description="Project access level and notification settings."
+ )
+ group_access: Optional[Dict] = Field(
+ default=None, description="Group access level and notification settings."
+ )
+
+
+class Statistics(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Statistics")
+ commit_count: Optional[int] = Field(
+ default=None, description="The number of commits in the project."
+ )
+ storage_size: Optional[int] = Field(
+ default=None, description="The total storage size of the project."
+ )
+ repository_size: Optional[int] = Field(
+ default=None, description="The size of the repository."
+ )
+ wiki_size: Optional[int] = Field(default=None, description="The size of the wiki.")
+ lfs_objects_size: Optional[int] = Field(
+ default=None, description="The size of LFS objects."
+ )
+ job_artifacts_size: Optional[int] = Field(
+ default=None, description="The size of job artifacts."
+ )
+ pipeline_artifacts_size: Optional[int] = Field(
+ default=None, description="The size of pipeline artifacts."
+ )
+ packages_size: Optional[int] = Field(
+ default=None, description="The size of packages."
+ )
+ snippets_size: Optional[int] = Field(
+ default=None, description="The size of snippets."
+ )
+ uploads_size: Optional[int] = Field(
+ default=None, description="The size of uploads."
+ )
+
+
+class Links(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Links")
+ self: Optional[str] = Field(default=None, description="URL to the project itself.")
+ issues: Optional[str] = Field(
+ default=None, description="URL to the project's issues."
+ )
+ merge_requests: Optional[str] = Field(
+ default=None, description="URL to the project's merge requests."
+ )
+ repo_branches: Optional[str] = Field(
+ default=None, description="URL to the project's repository branches."
+ )
+ labels: Optional[str] = Field(
+ default=None, description="URL to the project's labels."
+ )
+ events: Optional[str] = Field(
+ default=None, description="URL to the project's events."
+ )
+ members: Optional[str] = Field(
+ default=None, description="URL to the project's members."
+ )
+ cluster_agents: Optional[str] = Field(
+ default=None, description="URL to the project's cluster agents."
+ )
+ self_link: Optional[str] = Field(
+ default=None, alias="self", description="API URL to the issue itself."
+ )
+ notes: Optional[str] = Field(
+ default=None, description="API URL to the notes of the issue."
+ )
+ award_emoji: Optional[str] = Field(
+ default=None, description="API URL to the award emojis of the issue."
+ )
+ project: Optional[str] = Field(
+ default=None, description="API URL to the project of the issue."
+ )
+ closed_as_duplicate_of: Optional[str] = Field(
+ default=None,
+ description="API URL to the issue this one was closed as duplicate of.",
+ )
+
+
+class Diff(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Diff")
+ id: Optional[int] = Field(default=None, description="The ID of the Diff")
+ merge_request_id: Optional[int] = Field(
+ default=None, description="The merge request ID"
+ )
+ head_commit_sha: Optional[str] = Field(
+ default=None, description="The head commit sha"
+ )
+ base_commit_sha: Optional[str] = Field(
+ default=None, description="The base commit sha"
+ )
+ start_commit_sha: Optional[str] = Field(
+ default=None, description="The start commit sha"
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="Creation date of the note"
+ )
+ state: Optional[str] = Field(default=None, description="The state of the Diff")
+ real_size: Optional[str] = Field(
+ default=None, description="The real size of the Diff"
+ )
+ patch_id_sha: Optional[str] = Field(
+ default=None, description="The patch ID of the sha"
+ )
+ diff: Optional[str] = Field(default=None, description="The diff of the commit")
+ new_path: Optional[str] = Field(
+ default=None, description="The new path of the file"
+ )
+ old_path: Optional[str] = Field(
+ default=None, description="The old path of the file"
+ )
+ a_mode: Optional[str] = Field(
+ default=None, description="The file mode for the old file"
+ )
+ b_mode: Optional[str] = Field(
+ default=None, description="The file mode for the new file"
+ )
+ new_file: Optional[bool] = Field(
+ default=None, description="Whether this is a new file"
+ )
+ renamed_file: Optional[bool] = Field(
+ default=None, description="Whether this file was renamed"
+ )
+ deleted_file: Optional[bool] = Field(
+ default=None, description="Whether this file was deleted"
+ )
+ generated_file: Optional[bool] = Field(
+ default=None, description="Whether this file was generated"
+ )
+
+
+class Diffs(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Diffs")
+ diffs: List[Diff] = Field(default=None, description="List of diffs")
+
+
+class DetailedStatus(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="DetailedStatus")
+ icon: Optional[str] = Field(
+ default=None, description="The icon representing the status."
+ )
+ text: Optional[str] = Field(
+ default=None, description="The text describing the status."
+ )
+ label: Optional[str] = Field(default=None, description="The label of the status.")
+ group: Optional[str] = Field(
+ default=None, description="The group to which this status belongs."
+ )
+ tooltip: Optional[str] = Field(
+ default=None, description="The tooltip text for the status."
+ )
+ has_details: Optional[bool] = Field(
+ default=None, description="Indicates if the status has details."
+ )
+ details_path: Optional[str] = Field(
+ default=None, description="The path to the details of the status."
+ )
+ illustration: Optional[Any] = Field(
+ default=None, description="The illustration object related to the status."
+ )
+ favicon: Optional[str] = Field(
+ default=None, description="The URL to the favicon representing the status."
+ )
+
+
+class Pipeline(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Pipeline")
+ id: Optional[int] = Field(default=None, description="ID of the pipeline")
+ iid: Optional[int] = Field(
+ default=None, description="The internal ID of the pipeline."
+ )
+ ref: Optional[str] = Field(
+ default=None, description="Reference name of the pipeline"
+ )
+ sha: Optional[str] = Field(default=None, description="SHA of the pipeline")
+ status: Optional[str] = Field(default=None, description="Status of the pipeline")
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL for the pipeline"
+ )
+ project_id: Optional[int] = Field(
+ default=None, description="The ID of the project associated with the pipeline."
+ )
+ before_sha: Optional[str] = Field(
+ default=None, description="The commit SHA before the current one."
+ )
+ tag: Optional[bool] = Field(
+ default=None, description="Indicates if the pipeline is for a tag."
+ )
+ yaml_errors: Optional[str] = Field(
+ default=None,
+ description="Errors encountered in the pipeline YAML configuration.",
+ )
+ user: Optional[User] = Field(
+ default=None, description="The user who triggered the pipeline."
+ )
+ created_at: Optional[str] = Field(
+ default=None, description="Timestamp when the pipeline was created."
+ )
+ updated_at: Optional[str] = Field(
+ default=None, description="Timestamp when the pipeline was last updated."
+ )
+ started_at: Optional[str] = Field(
+ default=None, description="Timestamp when the pipeline started."
+ )
+ finished_at: Optional[str] = Field(
+ default=None, description="Timestamp when the pipeline finished."
+ )
+ committed_at: Optional[str] = Field(
+ default=None, description="Timestamp when the pipeline was committed."
+ )
+ duration: Optional[float] = Field(
+ default=None, description="The duration of the pipeline in seconds."
+ )
+ queued_duration: Optional[float] = Field(
+ default=None, description="The duration the pipeline spent in the queue."
+ )
+ coverage: Optional[str] = Field(
+ default=None, description="The code coverage percentage."
+ )
+ name: Optional[str] = Field(default=None, description="The name of the pipeline.")
+ source: Optional[str] = Field(
+ default=None, description="The source of the pipeline (e.g., push, web)."
+ )
+ detailed_status: Optional[DetailedStatus] = Field(
+ default=None, description="The detailed status of the pipeline."
+ )
+
+
+class Pipelines(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Pipelines")
+ pipelines: List[Pipeline] = Field(default=None, description="List of pipelines")
+
+
+class PackageLink(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="PackageLink")
+ web_path: Optional[str] = Field(
+ default=None, description="Web path to access the package"
+ )
+ delete_api_path: Optional[str] = Field(
+ default=None, description="API path to delete the package"
+ )
+
+
+class PackageVersion(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="PackageVersion")
+ id: Optional[int] = Field(default=None, description="Version ID of the package")
+ version: Optional[str] = Field(default=None, description="Version of the package")
+ created_at: Optional[datetime] = Field(
+ default=None, description="Creation date and time of the package version"
+ )
+ pipelines: Optional[List[Pipeline]] = Field(
+ default=None,
+ description="List of pipelines associated with the package version",
+ )
+
+
+class Package(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Package")
+ id: Optional[int] = Field(default=None, description="Package ID")
+ name: Optional[str] = Field(default=None, description="Name of the package")
+ version: Optional[str] = Field(default=None, description="Version of the package")
+ package_type: Optional[str] = Field(
+ default=None, description="Type of the package (e.g., maven, npm, conan)"
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="Creation date and time of the package"
+ )
+ last_downloaded_at: Optional[datetime] = Field(
+ default=None, description="Last downloaded date and time of the package"
+ )
+ conan_package_name: Optional[str] = Field(
+ default=None, description="Conan package name if applicable"
+ )
+ links: Optional[PackageLink] = Field(
+ default=None, alias="_links", description="Links related to the package"
+ )
+ pipelines: Optional[List[Pipeline]] = Field(
+ default=None, description="List of pipelines associated with the package"
+ )
+ tags: Optional[List[str]] = Field(
+ default=None, description="List of tags associated with the package"
+ )
+ versions: Optional[List[PackageVersion]] = Field(
+ default=None, description="List of different versions of the package"
+ )
+ package_id: Optional[int] = Field(
+ default=None, description="ID of the package this file belongs to"
+ )
+ file_name: Optional[str] = Field(
+ default=None, description="Name of the package file"
+ )
+ size: Optional[int] = Field(
+ default=None, description="Size of the package file in bytes"
+ )
+ file_md5: Optional[str] = Field(
+ default=None, description="MD5 checksum of the package file"
+ )
+ file_sha1: Optional[str] = Field(
+ default=None, description="SHA-1 checksum of the package file"
+ )
+ file_sha256: Optional[str] = Field(
+ default=None, description="SHA-256 checksum of the package file"
+ )
+
+
+class Packages(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Packages")
+ packages: List[Package] = Field(default=None, description="List of packages")
+
+
+class CommitStats(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="CommitStats")
+ additions: Optional[int] = Field(
+ default=None, description="Number of additions in the commit"
+ )
+ deletions: Optional[int] = Field(
+ default=None, description="Number of deletions in the commit"
+ )
+ total: Optional[int] = Field(
+ default=None, description="Total number of changes in the commit"
+ )
+
+
+class CommitSignature(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="CommitSignature")
+ signature_type: Optional[str] = Field(
+ default=None, description="Type of the signature"
+ )
+ verification_status: Optional[str] = Field(
+ default=None, description="Verification status of the signature"
+ )
+ commit_source: Optional[str] = Field(
+ default=None, description="Source of the commit"
+ )
+ gpg_key_id: Optional[int] = Field(default=None, description="ID of the GPG key")
+ gpg_key_primary_keyid: Optional[str] = Field(
+ default=None, description="Primary key ID of the GPG key"
+ )
+ gpg_key_user_name: Optional[str] = Field(
+ default=None, description="User name of the GPG key owner"
+ )
+ gpg_key_user_email: Optional[str] = Field(
+ default=None, description="User email of the GPG key owner"
+ )
+ gpg_key_subkey_id: Optional[str] = Field(
+ default=None, description="Subkey ID of the GPG key"
+ )
+ key: Optional[Dict[str, Any]] = Field(default=None, description="SSH key details")
+ x509_certificate: Optional[Dict[str, Any]] = Field(
+ default=None, description="X509 certificate details"
+ )
+ message: Optional[str] = Field(
+ default=None, description="The message from the signature response."
+ )
+
+
+class Comment(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Comment")
+ id: Optional[int] = Field(default=None, description="ID of the note")
+ type: Optional[str] = Field(default=None, description="Type of the note")
+ body: Optional[str] = Field(default=None, description="Body content of the note")
+ note: Optional[str] = Field(default=None, description="Content of the note")
+ attachment: Optional[Any] = Field(
+ default=None, description="Attachment associated with the note"
+ )
+ author: Optional[User] = Field(default=None, description="Author of the note")
+ created_at: Optional[datetime] = Field(
+ default=None, description="Creation date of the note"
+ )
+ updated_at: Optional[datetime] = Field(
+ default=None, description="Last update date of the note"
+ )
+ system: Optional[bool] = Field(
+ default=None, description="Whether the note is a system note"
+ )
+ noteable_id: Optional[int] = Field(
+ default=None, description="ID of the noteable entity"
+ )
+ noteable_type: Optional[str] = Field(
+ default=None, description="Type of the noteable entity"
+ )
+ resolvable: Optional[bool] = Field(
+ default=None, description="Whether the note is resolvable"
+ )
+ confidential: Optional[bool] = Field(
+ default=None, description="Whether the note is confidential"
+ )
+ noteable_iid: Optional[int] = Field(
+ default=None, description="IID of the noteable entity"
+ )
+ commands_changes: Optional[Dict[str, Any]] = Field(
+ default=None, description="Command changes associated with the note"
+ )
+ line_type: Optional[str] = Field(default=None, description="Line type")
+ path: Optional[str] = Field(default=None, description="Path")
+ line: Optional[int] = Field(default=None, description="Line in note")
+
+
+class Comments(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Comments")
+ comments: List[Comment] = Field(default=None, description="List of comments")
+
+
+class Commit(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Commit")
+ id: Optional[Union[str, int]] = Field(default=None, description="The commit ID.")
+ short_id: Optional[str] = Field(
+ default=None, description="A shortened version of the commit ID."
+ )
+ started_at: Optional[datetime] = Field(
+ default=None, description="The start date of the commit."
+ )
+ finished_at: Optional[datetime] = Field(
+ default=None, description="The finished date of the commit."
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="The creation date of the commit."
+ )
+ parent_ids: Optional[List[str]] = Field(
+ default=None, description="A list of parent commit IDs."
+ )
+ title: Optional[str] = Field(default=None, description="The title of the commit.")
+ description: Optional[str] = Field(
+ default=None, description="The commit description."
+ )
+ message: Optional[str] = Field(
+ default=None, description="The name of the commit author."
+ )
+ author: Optional[User] = Field(
+ default=None, description="The author of the commit."
+ )
+ author_name: Optional[str] = Field(
+ default=None, description="The name of the commit author."
+ )
+ author_email: Optional[str] = Field(
+ default=None, description="The email of the commit author."
+ )
+ authored_date: Optional[datetime] = Field(
+ default=None, description="The date the commit was authored."
+ )
+ committer_name: Optional[str] = Field(
+ default=None, description="The name of the committer."
+ )
+ committer_email: Optional[EmailStr] = Field(
+ default=None, description="The email of the committer."
+ )
+ committed_date: Optional[datetime] = Field(
+ default=None, description="The date the commit was committed."
+ )
+ name: Optional[str] = Field(default=None, description="The name of the commit.")
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The web URL for the commit."
+ )
+ trailers: Optional[Dict[str, Any]] = Field(
+ default=None, description="Trailers of the commit"
+ )
+ extended_trailers: Optional[Dict[str, List[str]]] = Field(
+ default=None, description="Extended trailers of the commit"
+ )
+ stats: Optional[CommitStats] = Field(
+ default=None, description="Statistics of the commit"
+ )
+ status: Optional[str] = Field(default=None, description="Status of the commit")
+ last_pipeline: Optional[Pipeline] = Field(
+ default=None, description="Last pipeline associated with the commit"
+ )
+ signature: Optional[CommitSignature] = Field(
+ default=None, description="Signature associated with the commit"
+ )
+ sha: Optional[str] = Field(default=None, description="SHA signature")
+ count: Optional[int] = Field(default=None, description="Commit count")
+ dry_run: Optional[str] = Field(default=None, description="Dry run status")
+ individual_note: Optional[bool] = Field(
+ default=None, description="Flag that this was a discussion"
+ )
+ notes: Optional[List[Comment]] = Field(
+ default=None, description="Discussion on commit"
+ )
+ allow_failure: Optional[bool] = Field(
+ default=None, description="Flag allows for failure"
+ )
+ target_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The target url for the commit."
+ )
+ ref: Optional[str] = Field(default=None, description="The ref of the commit.")
+ error_code: Optional[str] = Field(default=None, description="Error codes")
+ coverage: Optional[float] = Field(default=None, description="Coverage of commit")
+
+
+class Commits(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Commits")
+ commits: List[Commit] = Field(default=None, description="List of commits")
+
+
+class Membership(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Membership")
+ id: Optional[int] = Field(default=None, description="ID of the membership")
+ source_id: Optional[int] = Field(
+ default=None, description="Source ID of the membership"
+ )
+ source_full_name: Optional[str] = Field(
+ default=None, description="Full name of the source"
+ )
+ source_members_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL of the source members"
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="Timestamp of when the membership was created"
+ )
+ expires_at: Optional[datetime] = Field(
+ default=None, description="Timestamp of when the membership expires"
+ )
+ access_level: Optional[dict] = Field(
+ default=None, description="Access level details of the membership"
+ )
+
+
+class Memberships(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Memberships")
+ memberships: List[Membership] = Field(
+ default=None, description="List of memberships"
+ )
+
+
+class ApprovedByUser(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ApprovedByUser")
+ user: User = Field(
+ default=None, description="User who has approved the merge request"
+ )
+
+
+class Project(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Project")
+ id: Optional[int] = Field(default=None, description="The ID of the project.")
+ description: Optional[str] = Field(
+ default=None, description="The description of the project."
+ )
+ description_html: Optional[str] = Field(
+ default=None, description="The HTML description of the project."
+ )
+ name: Optional[str] = Field(default=None, description="The name of the project.")
+ name_with_namespace: Optional[str] = Field(
+ default=None, description="The name with namespace of the project."
+ )
+ path: Optional[str] = Field(default=None, description="The path of the project.")
+ path_with_namespace: Optional[str] = Field(
+ default=None, description="The path with namespace of the project."
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="The creation time of the project."
+ )
+ updated_at: Optional[datetime] = Field(
+ default=None, description="The last update time of the project."
+ )
+ default_branch: Optional[str] = Field(
+ default=None, description="The default branch of the project."
+ )
+ tag_list: Optional[List[str]] = Field(
+ default=None, description="Deprecated. Use `topics` instead."
+ )
+ topics: Optional[List[str]] = Field(
+ default=None, description="The topics of the project."
+ )
+ ssh_url_to_repo: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The SSH URL to the repository."
+ )
+ http_url_to_repo: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The HTTP URL to the repository."
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The web URL to the project."
+ )
+ readme_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The URL to the README file."
+ )
+ avatar_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The avatar URL of the project."
+ )
+ forks_count: Optional[int] = Field(default=None, description="The number of forks.")
+ star_count: Optional[int] = Field(default=None, description="The number of stars.")
+ last_activity_at: Optional[datetime] = Field(
+ default=None, description="The time of the last activity."
+ )
+ namespace: Optional[Namespace] = Field(
+ default=None, description="The namespace of the project."
+ )
+ container_registry_image_prefix: Optional[str] = Field(
+ default=None, description="The container registry image prefix."
+ )
+ additional_links: Optional[Links] = Field(
+ default=None, alias="_links", description="Related links."
+ )
+ packages_enabled: Optional[bool] = Field(
+ default=None, description="Whether packages are enabled."
+ )
+ empty_repo: Optional[bool] = Field(
+ default=None, description="Whether the repository is empty."
+ )
+ archived: Optional[bool] = Field(
+ default=None, description="Whether the project is archived."
+ )
+ visibility: Optional[str] = Field(
+ default=None, description="The visibility of the project."
+ )
+ resolve_outdated_diff_discussions: Optional[bool] = Field(
+ default=None, description="Whether outdated diff discussions are resolved."
+ )
+ container_expiration_policy: Optional[ContainerExpirationPolicy] = Field(
+ default=None, description="The container expiration policy."
+ )
+ issues_enabled: Optional[bool] = Field(
+ default=None, description="Whether issues are enabled."
+ )
+ merge_requests_enabled: Optional[bool] = Field(
+ default=None, description="Whether merge requests are enabled."
+ )
+ wiki_enabled: Optional[bool] = Field(
+ default=None, description="Whether the wiki is enabled."
+ )
+ jobs_enabled: Optional[bool] = Field(
+ default=None, description="Whether jobs are enabled."
+ )
+ snippets_enabled: Optional[bool] = Field(
+ default=None, description="Whether snippets are enabled."
+ )
+ container_registry_enabled: Optional[bool] = Field(
+ default=None,
+ description="Deprecated. Use `container_registry_access_level` instead.",
+ )
+ container_registry_access_level: Optional[str] = Field(
+ default=None, description="The access level for the container registry."
+ )
+ security_and_compliance_access_level: Optional[str] = Field(
+ default=None, description="The access level for security and compliance."
+ )
+ creator_id: Optional[int] = Field(
+ default=None, description="The ID of the creator."
+ )
+ import_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The import URL."
+ )
+ import_type: Optional[str] = Field(default=None, description="The import type.")
+ import_status: Optional[str] = Field(default=None, description="The import status.")
+ import_error: Optional[str] = Field(default=None, description="The import error.")
+ shared_runners_enabled: Optional[bool] = Field(
+ default=None, description="Whether shared runners are enabled."
+ )
+ group_runners_enabled: Optional[bool] = Field(
+ default=None, description="Whether group runners are enabled."
+ )
+ lfs_enabled: Optional[bool] = Field(
+ default=None, description="Whether LFS is enabled."
+ )
+ ci_default_git_depth: Optional[int] = Field(
+ default=None, description="The default git depth for CI."
+ )
+ ci_forward_deployment_enabled: Optional[bool] = Field(
+ default=None, description="Whether forward deployment is enabled for CI."
+ )
+ ci_forward_deployment_rollback_allowed: Optional[bool] = Field(
+ default=None,
+ description="Whether rollback is allowed for CI forward deployment.",
+ )
+ ci_allow_fork_pipelines_to_run_in_parent_project: Optional[bool] = Field(
+ default=None,
+ description="Whether fork pipelines can run in the parent project.",
+ )
+ ci_separated_caches: Optional[bool] = Field(
+ default=None, description="Whether CI caches are separated."
+ )
+ ci_restrict_pipeline_cancellation_role: Optional[str] = Field(
+ default=None, description="The role that can cancel pipelines."
+ )
+ public_jobs: Optional[bool] = Field(
+ default=None, description="Whether jobs are public."
+ )
+ shared_with_groups: Optional[List] = Field(
+ default=None, description="Groups the project is shared with."
+ )
+ only_allow_merge_if_pipeline_succeeds: Optional[bool] = Field(
+ default=None,
+ description="Whether merging is only allowed if the pipeline succeeds.",
+ )
+ allow_merge_on_skipped_pipeline: Optional[bool] = Field(
+ default=None, description="Whether merging is allowed on skipped pipelines."
+ )
+ restrict_user_defined_variables: Optional[bool] = Field(
+ default=None, description="Whether user-defined variables are restricted."
+ )
+ only_allow_merge_if_all_discussions_are_resolved: Optional[bool] = Field(
+ default=None,
+ description="Whether merging is only allowed if all discussions are resolved.",
+ )
+ remove_source_branch_after_merge: Optional[bool] = Field(
+ default=None, description="Whether the source branch is removed after merging."
+ )
+ request_access_enabled: Optional[bool] = Field(
+ default=None, description="Whether requesting access is enabled."
+ )
+ merge_method: Optional[str] = Field(
+ default=None, description="The method used for merging."
+ )
+ squash_option: Optional[str] = Field(default=None, description="The squash option.")
+ enforce_auth_checks_on_uploads: Optional[bool] = Field(
+ default=None, description="Whether auth checks are enforced on uploads."
+ )
+ suggestion_commit_message: Optional[str] = Field(
+ default=None, description="The suggestion commit message."
+ )
+ compliance_frameworks: Optional[List[str]] = Field(
+ default=None, description="The compliance frameworks."
+ )
+ issues_template: Optional[str] = Field(
+ default=None, description="The issues template."
+ )
+ merge_requests_template: Optional[str] = Field(
+ default=None, description="The merge requests template."
+ )
+ packages_relocation_enabled: Optional[bool] = Field(
+ default=None, description="Whether package relocation is enabled."
+ )
+ requirements_enabled: Optional[bool] = Field(
+ default=None, description="The requirements feature enabled status."
+ )
+ build_git_strategy: Optional[str] = Field(
+ default=None, description="The build git strategy."
+ )
+ build_timeout: Optional[int] = Field(default=None, description="The build timeout.")
+ auto_cancel_pending_pipelines: Optional[str] = Field(
+ default=None, description="The auto-cancel pending pipelines setting."
+ )
+ build_coverage_regex: Optional[str] = Field(
+ default=None, description="The build coverage regex."
+ )
+ ci_config_path: Optional[str] = Field(
+ default=None, description="The CI config path."
+ )
+ shared_runners_minutes_limit: Optional[int] = Field(
+ default=None, description="The shared runners minutes limit."
+ )
+ extra_shared_runners_minutes_limit: Optional[int] = Field(
+ default=None, description="The extra shared runners minutes limit."
+ )
+ printing_merge_request_link_enabled: Optional[bool] = Field(
+ default=None, description="Whether printing the merge request link is enabled."
+ )
+ merge_trains_enabled: Optional[bool] = Field(
+ default=None, description="Whether merge trains are enabled."
+ )
+ has_open_issues: Optional[bool] = Field(
+ default=None, description="Whether the project has open issues."
+ )
+ approvals_before_merge: Optional[int] = Field(
+ default=None, description="Number of approvals required before merging."
+ )
+ mirror: Optional[bool] = Field(
+ default=None, description="Whether the project is a mirror."
+ )
+ mirror_user_id: Optional[int] = Field(
+ default=None, description="The ID of the mirror user."
+ )
+ mirror_trigger_builds: Optional[bool] = Field(
+ default=None, description="Whether mirror builds are triggered."
+ )
+ only_mirror_protected_branches: Optional[bool] = Field(
+ default=None, description="Whether only protected branches are mirrored."
+ )
+ mirror_overwrites_diverged_branches: Optional[bool] = Field(
+ default=None, description="Whether diverged branches are overwritten."
+ )
+ permissions: Optional[Permissions] = Field(
+ default=None, description="The permissions settings."
+ )
+ statistics: Optional[Statistics] = Field(
+ default=None, description="The project statistics."
+ )
+ links: Optional[Links] = Field(default=None, description="Related links.")
+ service_desk_enabled: Optional[bool] = Field(
+ default=None, description="Service Desk Enabled"
+ )
+ can_create_merge_request_in: Optional[bool] = Field(
+ default=None, description="Can create merge request in"
+ )
+ repository_access_level: Optional[str] = Field(
+ default=None, description="Repository access level"
+ )
+ merge_requests_access_level: Optional[str] = Field(
+ default=None, description="Merge request access level"
+ )
+ issues_access_level: Optional[str] = Field(
+ default=None, description="Issue access level"
+ )
+ forking_access_level: Optional[str] = Field(
+ default=None, description="Forking access level"
+ )
+ wiki_access_level: Optional[str] = Field(
+ default=None, description="Wiki access level"
+ )
+ builds_access_level: Optional[str] = Field(
+ default=None, description="Build access level"
+ )
+ snippets_access_level: Optional[str] = Field(
+ default=None, description="Snippet access level"
+ )
+ pages_access_level: Optional[str] = Field(
+ default=None, description="Page access level"
+ )
+ analytics_access_level: Optional[str] = Field(
+ default=None, description="Analytics access level"
+ )
+ emails_disabled: Optional[str] = Field(default=None, description="Emails disabled")
+ emails_enabled: Optional[str] = Field(default=None, description="Emails enabled")
+ open_issues_count: Optional[int] = Field(
+ default=None, description="Open issues in project"
+ )
+ ci_job_token_scope_enabled: Optional[bool] = Field(
+ default=None, description="CI Job Token scope enabled"
+ )
+ merge_commit_template: Optional[str] = Field(
+ default=None, description="Merge commit template"
+ )
+ squash_commit_template: Optional[str] = Field(
+ default=None, description="Squash commit template"
+ )
+ issue_branch_template: Optional[str] = Field(
+ default=None, description="Squash commit template"
+ )
+ auto_devops_enabled: Optional[bool] = Field(
+ default=None, description="Autodevops enabled"
+ )
+ auto_devops_deploy_strategy: Optional[str] = Field(
+ default=None, description="Autodevops deploy strategy"
+ )
+ autoclose_referenced_issues: Optional[bool] = Field(
+ default=None, description="Autoclose referenced issues"
+ )
+ keep_latest_artifact: Optional[bool] = Field(
+ default=None, description="Keep latest artifact"
+ )
+ runner_token_expiration_interval: Optional[bool] = Field(
+ default=None, description="Runner token expiration interval"
+ )
+ external_authorization_classification_label: Optional[str] = Field(
+ default=None, description="External authorization classification label"
+ )
+ requirements_access_level: Optional[str] = Field(
+ default=None, description="Requirements access level"
+ )
+ security_and_compliance_enabled: Optional[bool] = Field(
+ default=None, description="Security compliance enabled"
+ )
+ warn_about_potentially_unwanted_characters: Optional[bool] = Field(
+ default=None, description="Warna bout potentially unwanted characters."
+ )
+ owner: Optional[User] = Field(default=None, description="Owner user")
+ runners_token: Optional[str] = Field(default=None, description="Runners token")
+ repository_storage: Optional[str] = Field(
+ default=None, description="Repository storage enabled"
+ )
+ service_desk_address: Optional[str] = Field(
+ default=None, description="Service desk address"
+ )
+ marked_for_deletion_at: Optional[str] = Field(
+ default=None, description="Marked for deletion at"
+ )
+ marked_for_deletion_on: Optional[str] = Field(
+ default=None, description="Marked for deletion on"
+ )
+ operations_access_level: Optional[str] = Field(
+ default=None, description="Access level of operations"
+ )
+ ci_dockerfile: Optional[str] = Field(default=None, description="Dockerfile for CI")
+ groups: Optional[List[Dict[str, int]]] = Field(
+ default=None, description="List of groups"
+ )
+
+
+class Projects(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Projects")
+ projects: List[Project] = Field(default=None, description="List of projects")
+
+
+class Runner(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Runner")
+ id: Optional[int] = Field(default=None, description="ID of the runner.")
+ description: Optional[str] = Field(
+ default=None, description="Description of the runner."
+ )
+ ip_address: Optional[str] = Field(
+ default=None, description="IP address of the runner."
+ )
+ active: Optional[bool] = Field(
+ default=None, description="Indicates if the runner is active."
+ )
+ paused: Optional[bool] = Field(
+ default=None, description="Indicates if the runner is paused."
+ )
+ is_shared: Optional[bool] = Field(
+ default=None, description="Indicates if the runner is shared."
+ )
+ runner_type: Optional[str] = Field(default=None, description="Type of the runner.")
+ name: Optional[str] = Field(default=None, description="Name of the runner.")
+ online: Optional[bool] = Field(
+ default=None, description="Indicates if the runner is online."
+ )
+ status: Optional[str] = Field(default=None, description="Status of the runner.")
+ contacted_at: Optional[datetime] = Field(
+ None, description="Last contacted date and time"
+ )
+ architecture: Optional[str] = Field(None, description="Architecture of the runner")
+ platform: Optional[str] = Field(None, description="Platform of the runner")
+ revision: Optional[str] = Field(None, description="Revision of the runner")
+ version: Optional[str] = Field(None, description="Version of the runner")
+ access_level: Optional[str] = Field(None, description="Access level of the runner")
+ maximum_timeout: Optional[int] = Field(
+ None, description="Maximum timeout for the runner"
+ )
+ maintenance_note: Optional[str] = Field(
+ None, description="Maintenance note for the runner"
+ )
+ projects: Optional[List[Project]] = Field(
+ None, description="List of projects associated with the runner"
+ )
+ tag_list: Optional[List[str]] = Field(
+ None, description="List of tags associated with the runner"
+ )
+
+
+class Runners(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Runners")
+ runners: List[Runner] = Field(default=None, description="List of runners")
+
+
+class Job(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Job")
+ commit: Optional[Commit] = Field(
+ default=None, description="Details of the commit associated with the job."
+ )
+ coverage: Optional[float] = Field(
+ default=None, description="Code coverage percentage."
+ )
+ archived: Optional[bool] = Field(
+ default=None, description="Indicates if the job is archived."
+ )
+ allow_failure: Optional[bool] = Field(
+ default=None, description="Indicates if the job is allowed to fail."
+ )
+ created_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the job was created."
+ )
+ started_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the job was started."
+ )
+ finished_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the job was finished."
+ )
+ erased_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the job was erased."
+ )
+ duration: Optional[float] = Field(
+ default=None, description="Duration of the job in seconds."
+ )
+ queued_duration: Optional[float] = Field(
+ default=None, description="Time the job spent queued before starting."
+ )
+ artifacts_file: Optional[ArtifactsFile] = Field(
+ default=None, description="Details of the artifacts file produced by the job."
+ )
+ artifacts: Optional[List[Artifact]] = Field(
+ default=None, description="List of artifacts produced by the job."
+ )
+ artifacts_expire_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the artifacts expire."
+ )
+ tag_list: Optional[List[str]] = Field(
+ default=None, description="List of tags associated with the job."
+ )
+ id: Optional[int] = Field(default=None, description="ID of the job.")
+ name: Optional[str] = Field(default=None, description="Name of the job.")
+ pipeline: Optional[Pipeline] = Field(
+ default=None, description="Details of the pipeline associated with the job."
+ )
+ ref: Optional[str] = Field(default=None, description="Reference of the job.")
+ runner: Optional[Runner] = Field(
+ default=None, description="Details of the runner that executed the job."
+ )
+ runner_manager: Optional[RunnerManager] = Field(
+ default=None, description="Details of the runner manager."
+ )
+ stage: Optional[str] = Field(default=None, description="Stage of the job.")
+ status: Optional[str] = Field(default=None, description="Status of the job.")
+ failure_reason: Optional[str] = Field(
+ default=None, description="Reason for the job failure."
+ )
+ tag: Optional[bool] = Field(
+ default=None, description="Indicates if the job is tagged."
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL to view the job on the web."
+ )
+ project: Optional[Project] = Field(
+ default=None, description="Details of the project associated with the job."
+ )
+ user: Optional[User] = Field(
+ default=None, description="Details of the user who created the job."
+ )
+ downstream_pipeline: Optional[Pipeline] = Field(
+ default=None, description="Downstream pipeline."
+ )
+
+
+class Jobs(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Jobs")
+ jobs: List[Job] = Field(default=None, description="List of jobs")
+
+
+class GroupAccess(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="GroupAccess")
+ access_level: Optional[int] = Field(
+ default=None, description="Access level for a group"
+ )
+
+
+class DefaultBranchProtectionDefaults(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="DefaultBranchProtectionDefaults")
+ allowed_to_push: Optional[List[GroupAccess]] = Field(
+ default=None, description="List of groups allowed to push"
+ )
+ allow_force_push: Optional[bool] = Field(
+ default=None, description="Whether force push is allowed"
+ )
+ allowed_to_merge: Optional[List[GroupAccess]] = Field(
+ default=None, description="List of groups allowed to merge"
+ )
+
+
+class Group(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Group")
+ id: Optional[int] = Field(default=None, description="The ID of the group")
+ name: Optional[str] = Field(default=None, description="The name of the group")
+ path: Optional[str] = Field(default=None, description="The path of the group")
+ description: Optional[str] = Field(
+ default=None, description="The description of the group"
+ )
+ visibility: Optional[str] = Field(
+ default=None, description="The visibility level of the group"
+ )
+ share_with_group_lock: Optional[bool] = Field(
+ default=None, description="Lock sharing with other groups"
+ )
+ require_two_factor_authentication: Optional[bool] = Field(
+ default=None, description="Whether 2FA is required"
+ )
+ two_factor_grace_period: Optional[int] = Field(
+ default=None, description="Grace period for 2FA enforcement"
+ )
+ project_creation_level: Optional[str] = Field(
+ default=None, description="Level required to create projects"
+ )
+ auto_devops_enabled: Optional[bool] = Field(
+ default=None, description="Whether Auto DevOps is enabled"
+ )
+ subgroup_creation_level: Optional[str] = Field(
+ default=None, description="Level required to create subgroups"
+ )
+ emails_disabled: Optional[bool] = Field(
+ default=None, description="Whether emails are disabled"
+ )
+ emails_enabled: Optional[bool] = Field(
+ default=None, description="Whether emails are enabled"
+ )
+ mentions_disabled: Optional[bool] = Field(
+ default=None, description="Whether mentions are disabled"
+ )
+ lfs_enabled: Optional[bool] = Field(
+ default=None, description="Whether Git LFS is enabled"
+ )
+ default_branch: Optional[str] = Field(
+ default=None, description="The default branch of the group"
+ )
+ default_branch_protection: Optional[int] = Field(
+ default=None, description="Protection level of the default branch"
+ )
+ default_branch_protection_defaults: Optional[DefaultBranchProtectionDefaults] = (
+ Field(default=None, description="Default branch protection settings")
+ )
+ avatar_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL of the group's avatar"
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="Web URL of the group"
+ )
+ request_access_enabled: Optional[bool] = Field(
+ default=None, description="Whether request access is enabled"
+ )
+ repository_storage: Optional[str] = Field(
+ default=None, description="Repository storage type"
+ )
+ full_name: Optional[str] = Field(default=None, description="Full name of the group")
+ full_path: Optional[str] = Field(default=None, description="Full path of the group")
+ file_template_project_id: Optional[int] = Field(
+ default=None, description="ID of the file template project"
+ )
+ parent_id: Optional[int] = Field(default=None, description="Parent ID of the group")
+ created_at: Optional[str] = Field(
+ default=None, description="Creation timestamp of the group"
+ )
+ statistics: Optional[Statistics] = Field(
+ default=None, description="Statistics of the group"
+ )
+ wiki_access_level: Optional[str] = Field(
+ default=None, description="Access level of the wiki"
+ )
+ duo_features_enabled: Optional[bool] = Field(
+ default=None, description="Whether Duo features are enabled"
+ )
+ lock_duo_features_enabled: Optional[bool] = Field(
+ default=None, description="Whether Duo features are locked"
+ )
+ runners_token: Optional[str] = Field(
+ default=None, description="Runners token for the group"
+ )
+ enabled_git_access_protocol: Optional[str] = Field(
+ default=None, description="Enabled Git access protocol"
+ )
+ shared_with_groups: Optional[List[Dict[str, Any]]] = Field(
+ default=None, description="Groups shared with this group"
+ )
+ prevent_sharing_groups_outside_hierarchy: Optional[bool] = Field(
+ default=None, description="Prevent sharing groups outside hierarchy"
+ )
+ projects: Optional[Union[List[Project], List[Dict[str, Any]]]] = Field(
+ default=None, description="Projects within the group"
+ )
+ shared_projects: Optional[Union[List[Project], List[Dict[str, Any]]]] = Field(
+ default=None, description="Projects within the group"
+ )
+ ip_restriction_ranges: Optional[Any] = Field(
+ default=None, description="IP Restriction Ranges"
+ )
+ math_rendering_limits_enabled: Optional[bool] = Field(
+ default=None, description="Math rendering limits enabled"
+ )
+ lock_math_rendering_limits_enabled: Optional[bool] = Field(
+ default=None, description="Math rendering limits locked"
+ )
+ shared_runners_minutes_limit: Optional[int] = Field(
+ default=None, description="Shared runners limit in minutes"
+ )
+ extra_shared_runners_minutes_limit: Optional[int] = Field(
+ default=None, description="Extra shared runners limit in minutes"
+ )
+ marked_for_deletion_on: Optional[str] = Field(
+ default=None, description="Marked for deletion on."
+ )
+ membership_lock: Optional[bool] = Field(
+ default=None, description="Membership locked"
+ )
+ ldap_cn: Optional[Any] = Field(default=None, description="LDAP CN information")
+ ldap_access: Optional[Any] = Field(default=None, description="LDAP Access")
+
+
+class Groups(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Groups")
+ groups: List[Group] = Field(default=None, description="List of groups")
+
+
+class Webhook(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Webhook")
+ id: int = Field(default=None, description="Unique identifier for the webhook")
+ url: Union[HttpUrl, str] = Field(
+ default=None, description="The URL the webhook should target"
+ )
+ name: str = Field(default=None, description="Name of the webhook")
+ description: str = Field(default=None, description="Description of the webhook")
+ group_id: int = Field(
+ default=None, description="Group ID to which the webhook belongs"
+ )
+ push_events: bool = Field(
+ default=None, description="Whether push events trigger the webhook"
+ )
+ push_events_branch_filter: str = Field(
+ default="", description="Branch filter for push events"
+ )
+ issues_events: bool = Field(
+ default=None, description="Whether issues events trigger the webhook"
+ )
+ confidential_issues_events: bool = Field(
+ default=None,
+ description="Whether confidential issues events trigger the webhook",
+ )
+ merge_requests_events: bool = Field(
+ default=None, description="Whether merge requests events trigger the webhook"
+ )
+ tag_push_events: bool = Field(
+ default=None, description="Whether tag push events trigger the webhook"
+ )
+ note_events: bool = Field(
+ default=None, description="Whether note events trigger the webhook"
+ )
+ confidential_note_events: bool = Field(
+ default=None, description="Whether confidential note events trigger the webhook"
+ )
+ job_events: bool = Field(
+ default=None, description="Whether job events trigger the webhook"
+ )
+ pipeline_events: bool = Field(
+ default=None, description="Whether pipeline events trigger the webhook"
+ )
+ wiki_page_events: bool = Field(
+ default=None, description="Whether wiki page events trigger the webhook"
+ )
+ deployment_events: bool = Field(
+ default=None, description="Whether deployment events trigger the webhook"
+ )
+ releases_events: bool = Field(
+ default=None, description="Whether releases events trigger the webhook"
+ )
+ subgroup_events: bool = Field(
+ default=None, description="Whether subgroup events trigger the webhook"
+ )
+ member_events: bool = Field(
+ default=None, description="Whether member events trigger the webhook"
+ )
+ enable_ssl_verification: bool = Field(
+ default=None, description="Whether SSL verification is enabled for the webhook"
+ )
+ repository_update_events: bool = Field(
+ default=False,
+ description="Whether repository update events trigger the webhook",
+ )
+ alert_status: Optional[str] = Field(
+ default=None, description="Status of the webhook, e.g., 'executable'"
+ )
+ disabled_until: Optional[datetime] = Field(
+ default=None, description="Timestamp until which the webhook is disabled"
+ )
+ url_variables: List[str] = Field(
+ default_factory=list, description="List of URL variables for the webhook"
+ )
+ created_at: datetime = Field(
+ default=None, description="Creation timestamp of the webhook"
+ )
+ resource_access_token_events: bool = Field(
+ default=None,
+ description="Whether resource access token events trigger the webhook",
+ )
+ custom_webhook_template: str = Field(
+ default=None, description="Custom webhook template JSON"
+ )
+
+
+class AccessLevel(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="AccessLevel")
+ id: Optional[int] = Field(default=None, description="Access level ID")
+ access_level: Optional[int] = Field(
+ default=None, description="Numeric access level"
+ )
+ access_level_description: Optional[str] = Field(
+ default=None, description="Description of the access level"
+ )
+ deploy_key_id: Optional[int] = Field(default=None, description="Deploy key ID")
+ user_id: Optional[int] = Field(default=None, description="User ID")
+ group_id: Optional[int] = Field(default=None, description="Group ID")
+
+
+class Branch(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Branch")
+ name: Optional[str] = Field(default=None, description="The name of the branch.")
+ merged: Optional[bool] = Field(
+ default=None, description="Whether the branch is merged."
+ )
+ protected: Optional[bool] = Field(
+ default=None, description="Whether the branch is protected."
+ )
+ default: Optional[bool] = Field(
+ default=None, description="Whether the branch is the default branch."
+ )
+ developers_can_push: Optional[bool] = Field(
+ default=None, description="Whether developers can push to the branch."
+ )
+ developers_can_merge: Optional[bool] = Field(
+ default=None, description="Whether developers can merge the branch."
+ )
+ can_push: Optional[bool] = Field(
+ default=None, description="Whether the user can push to the branch."
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="The web URL for the branch."
+ )
+ commit: Optional[Commit] = Field(
+ default=None, description="The commit associated with the branch."
+ )
+ id: Optional[int] = Field(default=None, description="Branch ID")
+ push_access_levels: Optional[List[AccessLevel]] = Field(
+ default=None, description="Push access levels for the branch"
+ )
+ merge_access_levels: Optional[List[AccessLevel]] = Field(
+ default=None, description="Merge access levels for the branch"
+ )
+ unprotect_access_levels: Optional[List[AccessLevel]] = Field(
+ default=None, description="Unprotect access levels for the branch"
+ )
+ allow_force_push: Optional[bool] = Field(
+ default=None, description="Whether force pushing is allowed"
+ )
+ code_owner_approval_required: Optional[bool] = Field(
+ default=None, description="Whether code owner approval is required"
+ )
+ inherited: Optional[bool] = Field(
+ default=None, description="Whether the branch is inherited"
+ )
+
+
+class Branches(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Branches")
+ branches: List[Branch] = Field(default=None, description="List of branches")
+
+
+class ApprovalRule(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ApprovalRule")
+ id: Optional[int] = Field(default=None, description="Approval rule ID")
+ name: Optional[str] = Field(default=None, description="Approval rule name")
+ rule_type: Optional[str] = Field(
+ default=None, description="Type of the approval rule"
+ )
+ eligible_approvers: Optional[List[User]] = Field(
+ default=None, description="List of eligible approvers"
+ )
+ approvals_required: Optional[int] = Field(
+ default=None, description="Number of required approvals"
+ )
+ users: Optional[List[User]] = Field(
+ default=None, description="List of associated users"
+ )
+ groups: Optional[List[Group]] = Field(
+ default=None, description="List of associated groups"
+ )
+ contains_hidden_groups: Optional[bool] = Field(
+ default=None, description="Whether the rule contains hidden groups"
+ )
+ protected_branches: Optional[List[Branch]] = Field(
+ default=None, description="List of protected branches the rule applies to"
+ )
+ applies_to_all_protected_branches: Optional[bool] = Field(
+ default=None, description="Whether the rule applies to all protected branches"
+ )
+ source_rule: Optional[str] = Field(
+ default=None, description="Source rule for merge request rules"
+ )
+ approved: Optional[bool] = Field(
+ default=None, description="Whether the rule is approved"
+ )
+ overridden: Optional[bool] = Field(
+ default=None, description="Whether the rule is overridden"
+ )
+ approved_by: Optional[List[User]] = Field(
+ default=None, description="List of users who approved"
+ )
+
+
+class ApprovalRules(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ApprovalRules")
+ approval_rules: List[ApprovalRule] = Field(
+ default=None, description="List of approval rules"
+ )
+
+
+class MergeRequest(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="MergeRequest")
+ id: Optional[int] = Field(default=None, description="ID of the merge request")
+ iid: Optional[int] = Field(
+ default=None, description="Internal ID of the merge request"
+ )
+ project_id: Optional[int] = Field(
+ default=None, description="ID of the project the merge request belongs to"
+ )
+ title: Optional[str] = Field(default=None, description="Title of the merge request")
+ description: Optional[str] = Field(
+ default=None, description="Description of the merge request"
+ )
+ state: Optional[str] = Field(default=None, description="State of the merge request")
+ created_at: Optional[datetime] = Field(
+ default=None, description="Creation date of the merge request"
+ )
+ updated_at: Optional[datetime] = Field(
+ default=None, description="Last update date of the merge request"
+ )
+ target_branch: Optional[str] = Field(
+ default=None, description="Target branch of the merge request"
+ )
+ source_branch: Optional[str] = Field(
+ default=None, description="Source branch of the merge request"
+ )
+ upvotes: Optional[int] = Field(
+ default=None, description="Number of upvotes the merge request has received"
+ )
+ downvotes: Optional[int] = Field(
+ default=None, description="Number of downvotes the merge request has received"
+ )
+ author: Optional[User] = Field(
+ default=None, description="Author of the merge request"
+ )
+ assignee: Optional[User] = Field(
+ default=None, description="Assignee of the merge request"
+ )
+ source_project_id: Optional[int] = Field(
+ default=None, description="ID of the source project"
+ )
+ target_project_id: Optional[int] = Field(
+ default=None, description="ID of the target project"
+ )
+ labels: Optional[List[str]] = Field(
+ default=None, description="List of labels assigned to the merge request"
+ )
+ work_in_progress: Optional[bool] = Field(
+ default=None, description="Whether the merge request is a work in progress"
+ )
+ milestone: Optional[Milestone] = Field(
+ default=None, description="Milestone associated with the merge request"
+ )
+ merge_when_pipeline_succeeds: Optional[bool] = Field(
+ default=None, description="Whether to merge when the pipeline succeeds"
+ )
+ merge_status: Optional[str] = Field(
+ default=None, description="Merge status of the merge request"
+ )
+ sha: Optional[str] = Field(default=None, description="SHA of the merge request")
+ merge_commit_sha: Optional[str] = Field(
+ default=None, description="Merge commit SHA of the merge request"
+ )
+ draft: Optional[bool] = Field(
+ default=None, description="Draft state of merge request"
+ )
+ squash_commit_sha: Optional[str] = Field(
+ default=None, description="Squash commit SHA of the merge request"
+ )
+ squash_on_merge: Optional[bool] = Field(
+ default=None, description="Squash commits on merge"
+ )
+ user_notes_count: Optional[int] = Field(
+ default=None, description="Number of user notes on the merge request"
+ )
+ discussion_locked: Optional[bool] = Field(
+ default=None, description="Whether the discussion is locked"
+ )
+ should_remove_source_branch: Optional[bool] = Field(
+ default=None, description="Whether the source branch should be removed"
+ )
+ force_remove_source_branch: Optional[bool] = Field(
+ default=None, description="Whether to force remove the source branch"
+ )
+ allow_collaboration: Optional[bool] = Field(
+ default=None, description="Whether collaboration is allowed"
+ )
+ allow_maintainer_to_push: Optional[bool] = Field(
+ default=None, description="Whether the maintainer can push"
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="Web URL of the merge request"
+ )
+ references: Optional[References] = Field(
+ default=None, description="References associated with the merge request"
+ )
+ reference: Optional[str] = Field(
+ default=None, description="Reference associated with the merge request"
+ )
+ time_stats: Optional[TimeStats] = Field(
+ default=None, description="Time statistics for the merge request"
+ )
+ squash: Optional[bool] = Field(
+ default=None, description="Whether the merge request should be squashed"
+ )
+ task_completion_status: Optional[TaskCompletionStatus] = Field(
+ default=None, description="Task completion status for the merge request"
+ )
+ has_conflicts: Optional[bool] = Field(
+ default=None, description="Whether the merge request has conflicts"
+ )
+ blocking_discussions_resolved: Optional[bool] = Field(
+ default=None, description="Whether blocking discussions are resolved"
+ )
+ changes: Optional[List[Diff]] = Field(
+ default=None, description="List of changes (diffs) in the merge request"
+ )
+ merged_by: Optional[User] = Field(
+ default=None, description="Merger of the merge request"
+ )
+ merged_at: Optional[datetime] = Field(
+ default=None, description="Date when the merge request was merged"
+ )
+ closed_by: Optional[User] = Field(
+ default=None, description="User who closed the merge request"
+ )
+ closed_at: Optional[datetime] = Field(
+ default=None, description="Date when the merge request was closed"
+ )
+ latest_build_started_at: Optional[datetime] = Field(
+ default=None, description="Start date of the latest build"
+ )
+ latest_build_finished_at: Optional[datetime] = Field(
+ default=None, description="Finish date of the latest build"
+ )
+ first_deployed_to_production_at: Optional[datetime] = Field(
+ default=None, description="Date when first deployed to production"
+ )
+ pipeline: Optional[Pipeline] = Field(
+ default=None, description="Pipeline associated with the merge request"
+ )
+ head_pipeline: Optional[Pipeline] = Field(
+ default=None, description="Head pipeline associated with the merge request"
+ )
+ diff_refs: Optional[Dict[str, Any]] = Field(
+ default=None, description="Diff references associated with the merge request"
+ )
+ user: Optional[Dict[str, Any]] = Field(
+ default=None, description="User-specific information"
+ )
+ changes_count: Optional[str] = Field(
+ default=None, description="Count of changes in the merge request"
+ )
+ rebase_in_progress: Optional[bool] = Field(
+ default=None, description="Whether a rebase is in progress"
+ )
+ approvals_before_merge: Optional[int] = Field(
+ default=None, description="Number of approvals required before merging"
+ )
+ tag_list: Optional[List[str]] = Field(
+ default=None, description="List of tags associated with the merge request"
+ )
+ reviewer: Optional[List[User]] = Field(
+ default=None, description="List of reviewers for the merge request"
+ )
+ review: Optional[Dict[str, Any]] = Field(
+ default=None, description="Review information associated with the merge request"
+ )
+ imported: Optional[bool] = Field(
+ default=None, description="Indicates if the merge request was imported"
+ )
+ imported_from: Optional[str] = Field(
+ default=None, description="Source from where the merge request was imported"
+ )
+ merge_user: Optional[User] = Field(
+ default=None,
+ description="User who merged the merge request (use instead of merged_by)",
+ )
+ prepared_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the merge request was prepared"
+ )
+ assignees: Optional[List[User]] = Field(
+ default=None, description="List of users assigned to the merge request"
+ )
+ reviewers: Optional[List[User]] = Field(
+ default=None, description="List of users reviewing the merge request"
+ )
+ detailed_merge_status: Optional[str] = Field(
+ default=None, description="Detailed status of the merge request mergeability"
+ )
+ subscribed: Optional[bool] = Field(
+ default=None, description="Subscribed to Merge Request"
+ )
+ overflow: Optional[bool] = Field(
+ default=None, description="Indicates if overflow is enabled"
+ )
+ diverged_commits_count: Optional[int] = Field(
+ default=None, description="Diverged commit count"
+ )
+ merge_error: Optional[Union[str, Any]] = Field(
+ default=None, description="Merge errors"
+ )
+ approvals_required: Optional[int] = Field(
+ default=None, description="Number of approvals required"
+ )
+ approvals_left: Optional[int] = Field(
+ default=None, description="Number of approvals left"
+ )
+ approved_by: Optional[List[ApprovedByUser]] = Field(
+ default=None, description="List of users who approved"
+ )
+ approval_rules_overwritten: Optional[bool] = Field(
+ default=None, description="Allow override of approval rules"
+ )
+ rules: Optional[List[ApprovalRule]] = Field(
+ default=None, description="List of merge request rules"
+ )
+
+
+class MergeRequests(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="MergeRequests")
+ merge_requests: List[MergeRequest] = Field(
+ default=None, description="List of merge requests"
+ )
+
+
+class Epic(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Epic")
+ id: Optional[int] = Field(
+ default=None, description="Unique identifier for the epic."
+ )
+ iid: Optional[int] = Field(
+ default=None, description="Internal ID of the epic within the project."
+ )
+ title: Optional[str] = Field(default=None, description="Title of the epic.")
+ url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL to the epic."
+ )
+ group_id: Optional[int] = Field(
+ default=None, description="Group ID to which the epic belongs."
+ )
+
+
+class Issue(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Issue")
+ state: Optional[str] = Field(
+ default=None, description="State of the issue, e.g., opened or closed."
+ )
+ description: Optional[str] = Field(
+ default=None, description="Description of the issue."
+ )
+ author: Optional[User] = Field(default=None, description="Author of the issue.")
+ milestone: Optional[Milestone] = Field(
+ default=None, description="Milestone associated with the issue."
+ )
+ project_id: Optional[int] = Field(
+ default=None, description="Unique identifier for the project."
+ )
+ assignees: Optional[List[User]] = Field(
+ default=None, description="List of assignees for the issue."
+ )
+ assignee: Optional[User] = Field(default=None, description="Assignee of the issue.")
+ type: Optional[str] = Field(default=None, description="Type of the issue.")
+ updated_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the issue was last updated."
+ )
+ closed_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the issue was closed."
+ )
+ closed_by: Optional[User] = Field(
+ default=None, description="User who closed the issue."
+ )
+ changes_count: Optional[str] = Field(
+ default=None, description="Count of changes in the issue"
+ )
+ id: Optional[int] = Field(
+ default=None, description="Unique identifier for the issue."
+ )
+ title: Optional[str] = Field(default=None, description="Title of the issue.")
+ created_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the issue was created."
+ )
+ moved_to_id: Optional[int] = Field(
+ default=None, description="ID of the issue to which this issue was moved."
+ )
+ iid: Optional[int] = Field(
+ default=None, description="Internal ID of the issue within the project."
+ )
+ labels: Optional[List[str]] = Field(
+ default=None, description="Labels associated with the issue."
+ )
+ upvotes: Optional[int] = Field(
+ default=None, description="Number of upvotes the issue has received."
+ )
+ downvotes: Optional[int] = Field(
+ default=None, description="Number of downvotes the issue has received."
+ )
+ merge_requests_count: Optional[int] = Field(
+ default=None, description="Number of merge requests related to the issue."
+ )
+ user_notes_count: Optional[int] = Field(
+ default=None, description="Number of user notes on the issue."
+ )
+ iteration: Optional[Iteration] = Field(
+ default=None, description="Iteration of issue."
+ )
+ due_date: Optional[str] = Field(default=None, description="Due date for the issue.")
+ imported: Optional[bool] = Field(
+ default=None,
+ description="Indicates if the issue was imported from another system.",
+ )
+ imported_from: Optional[str] = Field(
+ default=None, description="Source from which the issue was imported."
+ )
+ web_url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="Web URL to view the issue."
+ )
+ references: Optional[References] = Field(
+ default=None, description="References of the issue."
+ )
+ time_stats: Optional[TimeStats] = Field(
+ default=None, description="Time statistics for the issue."
+ )
+ has_tasks: Optional[bool] = Field(
+ default=None, description="Indicates if the issue has tasks."
+ )
+ task_status: Optional[str] = Field(
+ default=None, description="Status of the tasks in the issue."
+ )
+ confidential: Optional[bool] = Field(
+ default=None, description="Indicates if the issue is confidential."
+ )
+ discussion_locked: Optional[bool] = Field(
+ default=None, description="Indicates if discussion on the issue is locked."
+ )
+ issue_type: Optional[str] = Field(default=None, description="Type of the issue.")
+ severity: Optional[str] = Field(
+ default=None, description="Severity level of the issue."
+ )
+ links: Optional[Links] = Field(
+ default=None, alias="_links", description="Links related to the issue."
+ )
+ task_completion_status: Optional[TaskCompletionStatus] = Field(
+ default=None, description="Completion status of tasks in the issue."
+ )
+ weight: Optional[int] = Field(default=None, description="Weight of the issue.")
+ epic_iid: Optional[int] = Field(
+ default=None, description="Deprecated, use `iid` of the `epic` attribute."
+ )
+ epic: Optional[Epic] = Field(
+ default=None, description="Epic to which the issue belongs."
+ )
+ health_status: Optional[str] = Field(
+ default=None,
+ description="Health status of the issue, e.g., on track or at risk.",
+ )
+ subscribed: Optional[bool] = Field(
+ default=None, description="Indicates if the user is subscribed to the issue."
+ )
+ service_desk_reply_to: Optional[str] = Field(
+ default=None, description="Service desk email for replies related to the issue."
+ )
+ blocking_issues_count: Optional[int] = Field(
+ default=None, description="Blocking issue count."
+ )
+
+
+class Issues(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Issues")
+ issues: List[Issue] = Field(default=None, description="List of issues")
+
+
+class PipelineVariable(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="PipelineVariable")
+ key: Optional[str] = Field(default=None, description="The key of the variable.")
+ variable_type: Optional[str] = Field(
+ default=None, description="The type of the variable (e.g., env_var)."
+ )
+ value: Optional[str] = Field(default=None, description="The value of the variable.")
+
+
+class PipelineVariables(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="PipelineVariables")
+ pipeline_variables: List[PipelineVariable] = Field(
+ default=None, description="List of pipeline variables"
+ )
+
+
+class TestCase(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="TestCase")
+ status: Optional[str] = Field(
+ default=None, description="The status of the test case (e.g., success, failed)."
+ )
+ name: Optional[str] = Field(default=None, description="The name of the test case.")
+ classname: Optional[str] = Field(
+ default=None, description="The class name of the test case."
+ )
+ execution_time: Optional[float] = Field(
+ default=None, description="The execution time of the test case in seconds."
+ )
+ system_output: Optional[str] = Field(
+ default=None, description="The system output of the test case."
+ )
+ stack_trace: Optional[str] = Field(
+ default=None, description="The stack trace of the test case if it failed."
+ )
+
+
+class TestSuite(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="TestSuite")
+ name: Optional[str] = Field(default=None, description="The name of the test suite.")
+ total_time: Optional[float] = Field(
+ default=None, description="The total time of the test suite in seconds."
+ )
+ total_count: Optional[int] = Field(
+ default=None, description="The total number of test cases in the suite."
+ )
+ success_count: Optional[int] = Field(
+ default=None, description="The number of successful test cases."
+ )
+ failed_count: Optional[int] = Field(
+ default=None, description="The number of failed test cases."
+ )
+ skipped_count: Optional[int] = Field(
+ default=None, description="The number of skipped test cases."
+ )
+ error_count: Optional[int] = Field(
+ default=None, description="The number of test cases with errors."
+ )
+ test_cases: Optional[List[TestCase]] = Field(
+ default=None, description="A list of test cases in the suite."
+ )
+ build_ids: Optional[List[int]] = Field(
+ default=None, description="A list of build IDs related to the test suite."
+ )
+ suite_error: Optional[str] = Field(
+ default=None, description="Errors encountered in the test suite."
+ )
+
+
+class TestReportTotal(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="TestReportTotal")
+ time: Optional[int] = Field(
+ default=None, description="The total time for all test cases in seconds."
+ )
+ count: Optional[int] = Field(
+ default=None, description="The total number of test cases."
+ )
+ success: Optional[int] = Field(
+ default=None, description="The total number of successful test cases."
+ )
+ failed: Optional[int] = Field(
+ default=None, description="The total number of failed test cases."
+ )
+ skipped: Optional[int] = Field(
+ default=None, description="The total number of skipped test cases."
+ )
+ error: Optional[int] = Field(
+ default=None, description="The total number of test cases with errors."
+ )
+ suite_error: Optional[str] = Field(
+ default=None, description="Errors encountered in the test suite."
+ )
+
+
+class TestReport(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="TestReport")
+ total: Optional[TestReportTotal] = Field(
+ default=None, description="Total count in test report."
+ )
+ test_suites: Optional[List[TestSuite]] = Field(
+ default=None, description="A list of test suites in the report."
+ )
+ total_time: Optional[int] = Field(
+ default=None, description="Total time of test report"
+ )
+ total_count: Optional[int] = Field(
+ default=None, description="Total count of test report"
+ )
+ success_count: Optional[int] = Field(
+ default=None, description="Success count of test report"
+ )
+ failed_count: Optional[int] = Field(
+ default=None, description="Failed count of test report"
+ )
+ skipped_count: Optional[int] = Field(
+ default=None, description="Skipped count of test report"
+ )
+ error_count: Optional[int] = Field(
+ default=None, description="Error count of test report"
+ )
+
+
+class MergeApprovals(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="MergeApprovals")
+ approvers: Optional[List[User]] = Field(
+ default=None, description="List of approvers"
+ )
+ approver_groups: Optional[List[Group]] = Field(
+ default=None, description="List of approver groups"
+ )
+ approvals_before_merge: Optional[int] = Field(
+ default=None, description="Number of approvals required before merge"
+ )
+ reset_approvals_on_push: Optional[bool] = Field(
+ default=None, description="Whether approvals reset on new push"
+ )
+ selective_code_owner_removals: Optional[bool] = Field(
+ default=None, description="Whether selective code owner removals are allowed"
+ )
+ disable_overriding_approvers_per_merge_request: Optional[bool] = Field(
+ default=None,
+ description="Whether overriding approvers per merge request is disabled",
+ )
+ merge_requests_author_approval: Optional[bool] = Field(
+ default=None, description="Whether authors can approve their own merge requests"
+ )
+ merge_requests_disable_committers_approval: Optional[bool] = Field(
+ default=None, description="Whether committers are disabled from approving"
+ )
+ require_password_to_approve: Optional[bool] = Field(
+ default=None, description="Whether a password is required to approve"
+ )
+
+
+class DeployToken(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="DeployToken")
+ id: Optional[int] = Field(
+ default=None, description="Unique identifier for the deploy token"
+ )
+ user_id: Optional[int] = Field(default=None, description="User ID.")
+ name: Optional[str] = Field(default=None, description="Name of the deploy token")
+ username: Optional[str] = Field(
+ default=None, description="Username associated with the deploy token"
+ )
+ expires_at: Optional[datetime] = Field(
+ default=None, description="Expiration date of the deploy token"
+ )
+ token: Optional[str] = Field(
+ default=None, description="The actual deploy token string"
+ )
+ revoked: Optional[bool] = Field(
+ default=None, description="Indicates whether the token has been revoked"
+ )
+ expired: Optional[bool] = Field(
+ default=None, description="Indicates whether the token has expired"
+ )
+ scopes: Optional[List[str]] = Field(
+ default=None, description="List of scopes assigned to the deploy token"
+ )
+ active: Optional[bool] = Field(default=None, description="Active token")
+ last_used_at: Optional[Any] = Field(default=None, description="Last used at")
+ created_at: Optional[datetime] = Field(
+ default=None, description="Creation date and time of the token"
+ )
+
+
+class DeployTokens(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="DeployTokens")
+ deploy_tokens: List[DeployToken] = Field(
+ default=None, description="List of deploy tokens"
+ )
+
+
+class Rule(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Rule")
+ id: int = Field(default=None, description="Unique identifier for the rule")
+ created_at: datetime = Field(
+ default=None, description="Timestamp when the rule was created"
+ )
+ commit_committer_check: bool = Field(
+ default=False, description="Check for committer compliance"
+ )
+ commit_committer_name_check: bool = Field(
+ default=False, description="Check for committer's name compliance"
+ )
+ reject_unsigned_commits: bool = Field(
+ default=False, description="Flag to reject unsigned commits"
+ )
+ commit_message_regex: Optional[str] = Field(
+ default=None, description="Regex for validating commit messages"
+ )
+ commit_message_negative_regex: Optional[str] = Field(
+ default=None, description="Negative regex for commit messages"
+ )
+ branch_name_regex: Optional[str] = Field(
+ default=None, description="Regex for validating branch names"
+ )
+ deny_delete_tag: bool = Field(
+ default=False, description="Flag to deny deletion of tags"
+ )
+ member_check: bool = Field(default=False, description="Check for valid membership")
+ prevent_secrets: bool = Field(
+ default=False, description="Flag to prevent secrets in commits"
+ )
+ author_email_regex: Optional[str] = Field(
+ default=None, description="Regex for author's email validation"
+ )
+ file_name_regex: Optional[str] = Field(
+ default=None, description="Regex for file name validation"
+ )
+ max_file_size: Optional[int] = Field(
+ default=None, description="Maximum file size allowed in MB"
+ )
+
+
+class AccessControl(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="AccessControl")
+ name: str = Field(default=None, description="Name of the access group")
+ access_level: Optional[int] = Field(
+ default=None, description="Access level as an integer"
+ )
+ member_role_id: Optional[int] = Field(
+ default=None, description="Role ID for the member in the group"
+ )
+
+
+class Source(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Source")
+ format: Optional[str] = Field(
+ default=None, description="Format of the source file (e.g., zip, tar.gz)"
+ )
+ url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL to download the source file"
+ )
+
+
+class Link(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Link")
+ id: Optional[int] = Field(default=None, description="Link ID")
+ name: Optional[str] = Field(default=None, description="Name of the link")
+ url: Optional[Union[HttpUrl, str]] = Field(
+ default=None, description="URL of the link"
+ )
+ link_type: Optional[str] = Field(
+ default=None, description="Type of the link (e.g., other)"
+ )
+
+
+class Assets(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Assets")
+ count: Optional[int] = Field(default=None, description="Total count of assets")
+ sources: Optional[List[Source]] = Field(
+ default=None, description="List of source files"
+ )
+ links: Optional[List[Link]] = Field(
+ default=None, description="List of additional links"
+ )
+ evidence_file_path: Optional[str] = Field(
+ default=None, description="URL to the evidence file"
+ )
+
+
+class Evidence(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Evidence")
+ sha: Optional[str] = Field(
+ default=None, description="SHA checksum of the evidence file"
+ )
+ filepath: Optional[str] = Field(
+ default=None, description="Filepath of the evidence file"
+ )
+ collected_at: Optional[datetime] = Field(
+ default=None, description="Timestamp when the evidence was collected"
+ )
+
+
+class ReleaseLinks(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ReleaseLinks")
+ closed_issues_url: Optional[Union[HttpUrl, str]] = Field(
+ None, description="URL to the list of closed issues"
+ )
+ closed_merge_requests_url: Optional[Union[HttpUrl, str]] = Field(
+ None, description="URL to the list of closed merge requests"
+ )
+ edit_url: Optional[Union[HttpUrl, str]] = Field(
+ None, description="URL to edit the release"
+ )
+ merged_merge_requests_url: Optional[Union[HttpUrl, str]] = Field(
+ None, description="URL to the list of merged merge requests"
+ )
+ opened_issues_url: Optional[Union[HttpUrl, str]] = Field(
+ None, description="URL to the list of opened issues"
+ )
+ opened_merge_requests_url: Optional[Union[HttpUrl, str]] = Field(
+ None, description="URL to the list of opened merge requests"
+ )
+ self: Optional[str] = Field(None, description="Self-referencing URL")
+
+
+class Release(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Release")
+ tag_name: Optional[str] = Field(default=None, description="Tag name of the release")
+ description: Optional[str] = Field(
+ default=None, description="Description of the release"
+ )
+ name: Optional[str] = Field(default=None, description="Name of the release")
+ created_at: Optional[datetime] = Field(
+ default=None, description="Creation date and time of the release"
+ )
+ released_at: Optional[datetime] = Field(
+ default=None, description="Release date and time"
+ )
+ author: Optional[User] = Field(default=None, description="Author of the release")
+ commit: Optional[Commit] = Field(
+ default=None, description="Commit associated with the release"
+ )
+ milestones: Optional[List[Milestone]] = Field(
+ default=None, description="List of milestones related to the release"
+ )
+ commit_path: Optional[str] = Field(
+ default=None, description="Path to the commit associated with the release"
+ )
+ tag_path: Optional[str] = Field(
+ default=None, description="Path to the tag associated with the release"
+ )
+ assets: Optional[Assets] = Field(
+ default=None, description="Assets related to the release"
+ )
+ evidences: Optional[List[Evidence]] = Field(
+ default=None, description="List of evidences related to the release"
+ )
+ links: Optional[ReleaseLinks] = Field(
+ default=None, alias="_links", description="Links related to the release"
+ )
+ evidence_sha: Optional[str] = Field(default=None, description="Evidence hash")
+
+
+class Releases(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Releases")
+ releases: List[Release] = Field(default=None, description="List of releases")
+
+
+class Token(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Token")
+ id: Optional[int] = Field(None, description="Token ID")
+ token: Optional[str] = Field(None, description="Authentication token")
+ token_expires_at: Optional[datetime] = Field(
+ None, description="Expiration date and time of the token"
+ )
+
+
+class ToDo(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ToDo")
+ id: int = Field(default=None, description="To-do identifier")
+ project: Project = Field(
+ default=None, description="Project associated with the to-do"
+ )
+ author: User = Field(default=None, description="Author of the to-do")
+ action_name: str = Field(default=None, description="Action taken in the to-do")
+ target_type: str = Field(
+ default=None, description="Type of target referenced in the to-do"
+ )
+ target: Issue = Field(default=None, description="Target issue for the to-do")
+ target_url: Union[HttpUrl, str] = Field(
+ default=None, description="URL pointing to the target of the to-do"
+ )
+ body: str = Field(default=None, description="Body text of the to-do")
+ state: str = Field(default=None, description="State of the to-do")
+ created_at: datetime = Field(
+ default=None, description="Timestamp when the to-do was created"
+ )
+
+
+class WikiPage(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="WikiPage")
+ content: Optional[str] = Field(None, description="Content of the wiki page")
+ format: Optional[str] = Field(
+ None, description="Format of the wiki page content (e.g., markdown, rdoc)"
+ )
+ slug: Optional[str] = Field(
+ None, description="Slug (URL-friendly identifier) of the wiki page"
+ )
+ title: Optional[str] = Field(None, description="Title of the wiki page")
+ encoding: Optional[str] = Field(
+ None, description="Encoding of the wiki page content (e.g., UTF-8)"
+ )
+
+
+class WikiPages(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="WikiPages")
+ wiki_pages: List[WikiPage] = Field(default=None, description="List of wiki pages")
+
+
+class WikiAttachmentLink(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="WikiAttachmentLink")
+ url: Optional[Union[HttpUrl, str]] = Field(
+ None, description="URL of the uploaded attachment"
+ )
+ markdown: Optional[str] = Field(
+ None, description="Markdown to embed the uploaded attachment"
+ )
+
+
+class WikiAttachment(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="WikiAttachment")
+ file_name: Optional[str] = Field(None, description="Name of the uploaded file")
+ file_path: Optional[str] = Field(None, description="Path where the file is stored")
+ branch: Optional[str] = Field(
+ None, description="Branch where the attachment is uploaded"
+ )
+ link: Optional[WikiAttachmentLink] = Field(
+ None, description="Link information for the uploaded attachment"
+ )
+
+
+class ProjectConfig(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="ProjectConfig")
+ id: int = Field(default=None, description="Project identifier")
+ description: Optional[str] = Field(None, description="Description of the project")
+ name: str = Field(default=None, description="Name of the project")
+ name_with_namespace: str = Field(
+ default=None, description="Full project name with namespace"
+ )
+ path: str = Field(default=None, description="Path of the project")
+ path_with_namespace: str = Field(
+ default=None, description="Full path of the project including namespace"
+ )
+ created_at: datetime = Field(
+ default=None, description="Creation timestamp of the project"
+ )
+
+
+class Agent(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Agent")
+ id: int = Field(default=None, description="Agent identifier")
+ config_project: ProjectConfig = Field(
+ default=None, description="Configuration project associated with the agent"
+ )
+
+
+class Agents(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ __hash__ = object.__hash__
+ base_type: str = Field(default="Agents")
+ allowed_agents: List[Agent] = Field(
+ default=None, description="List of allowed agents"
+ )
+ job: Job = Field(default=None, description="Job associated with the agents")
+ pipeline: Pipeline = Field(
+ default=None, description="Pipeline associated with the agents"
+ )
+ project: Project = Field(
+ default=None, description="Project associated with the agents"
+ )
+ user: User = Field(default=None, description="User associated with the agents")
+
+
+class Response(BaseModel):
+ model_config = ConfigDict(extra="forbid")
+ base_type: str = Field(default="Response")
+ data: Optional[
+ Union[
+ List,
+ Dict,
+ Agents,
+ Agent,
+ Branches,
+ Branch,
+ Pipelines,
+ Pipeline,
+ Commits,
+ Commit,
+ PipelineVariable,
+ PipelineVariables,
+ CommitSignature,
+ Diffs,
+ Diff,
+ Comments,
+ Comment,
+ Users,
+ User,
+ Memberships,
+ Membership,
+ Releases,
+ Release,
+ Issues,
+ Issue,
+ ToDo,
+ TestReport,
+ MergeRequests,
+ MergeRequest,
+ MergeApprovals,
+ ApprovalRules,
+ ApprovalRule,
+ Runners,
+ Runner,
+ Jobs,
+ Job,
+ Packages,
+ Package,
+ DeployTokens,
+ DeployToken,
+ AccessLevel,
+ AccessControl,
+ Rule,
+ Groups,
+ Group,
+ Projects,
+ Project,
+ TimeStats,
+ Token,
+ WikiPage,
+ WikiPages,
+ WikiAttachment,
+ Webhook,
+ ]
+ ] = Field(default=None, description="Data")
+ status_code: Union[str, int] = Field(
+ default=None, description="Response status code"
+ )
+ json_output: Optional[Union[List, Dict]] = Field(
+ default=None, description="Response JSON data"
+ )
+ raw_output: Optional[bytes] = Field(default=None, description="Response Raw bytes")
+
+ @field_validator("data")
+ def determine_model_type(cls, value):
+ single_models = {
+ "Agents": Agents,
+ "Branch": Branch,
+ "Pipeline": Pipeline,
+ "Commit": Commit,
+ "PipelineVariable": PipelineVariable,
+ "CommitSignature": CommitSignature,
+ "Diff": Diff,
+ "Comment": Comment,
+ "Issue": Issue,
+ "ToDo": ToDo,
+ "TestReport": TestReport,
+ "MergeRequest": MergeRequest,
+ "MergeApprovals": MergeApprovals,
+ "Release": Release,
+ "User": User,
+ "Membership": Membership,
+ "DeployToken": DeployToken,
+ "Group": Group,
+ "Job": Job,
+ "Package": Package,
+ "AccessLevel": AccessLevel,
+ "AccessControl": AccessControl,
+ "Rule": Rule,
+ "Project": Project,
+ "TimeStats": TimeStats,
+ "Token": Token,
+ "WikiPage": WikiPage,
+ "WikiAttachment": WikiAttachment,
+ "Webhook": Webhook,
+ "ApprovalRule": ApprovalRule,
+ "Runner": Runner,
+ }
+ temp_value = None
+ if isinstance(value, list):
+ if all(isinstance(item, Dict) for item in value):
+ try:
+ branches = [Branch(**item) for item in value]
+ temp_value = Branches(branches=branches)
+ logging.info(f"Branches Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Branches Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ commits = [Commit(**item) for item in value]
+ temp_value = Commits(commits=commits)
+ logging.info(f"Commits Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Commits Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ pipelines = [Pipeline(**item) for item in value]
+ temp_value = Pipelines(pipelines=pipelines)
+ logging.info(f"Pipelines Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Pipelines Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ merge_requests = [MergeRequest(**item) for item in value]
+ temp_value = MergeRequests(merge_requests=merge_requests)
+ logging.info(f"Merge Requests Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Merge Requests Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ releases = [Release(**item) for item in value]
+ temp_value = Releases(releases=releases)
+ logging.info(f"Releases Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Releases Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ diffs = [Diff(**item) for item in value]
+ temp_value = Diffs(diffs=diffs)
+ logging.info(f"Diffs Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Diffs Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ comments = [Comment(**item) for item in value]
+ temp_value = Comments(comments=comments)
+ logging.info(f"Comments Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Comments Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ deploy_tokens = [DeployToken(**item) for item in value]
+ temp_value = DeployTokens(deploy_tokens=deploy_tokens)
+ logging.info(f"Deploy Tokens Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Deploy Tokens Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ users = [User(**item) for item in value]
+ temp_value = Users(users=users)
+ logging.info(f"Users Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Users Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ memberships = [Membership(**item) for item in value]
+ temp_value = Memberships(memberships=memberships)
+ logging.info(f"Memberships Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Memberships Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ groups = [Group(**item) for item in value]
+ temp_value = Groups(groups=groups)
+ logging.info(f"Groups Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Groups Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ pipeline_variables = [PipelineVariable(**item) for item in value]
+ temp_value = PipelineVariables(
+ pipeline_variables=pipeline_variables
+ )
+ logging.info(f"PipelineVariable Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n PipelineVariable Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ projects = [Project(**item) for item in value]
+ temp_value = Projects(projects=projects)
+ logging.info(f"Projects Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Projects Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ issues = [Issue(**item) for item in value]
+ temp_value = Issues(issues=issues)
+ logging.info(f"Issues Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Issues Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ wiki_pages = [WikiPage(**item) for item in value]
+ temp_value = WikiPages(wiki_pages=wiki_pages)
+ logging.info(f"WikiPages Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n WikiPages Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ approval_rules = [ApprovalRule(**item) for item in value]
+ temp_value = ApprovalRules(approval_rules=approval_rules)
+ logging.info(f"ApprovalRules Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n ApprovalRules Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ jobs = [Job(**item) for item in value]
+ temp_value = Jobs(jobs=jobs)
+ logging.info(f"Jobs Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Jobs Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ packages = [Package(**item) for item in value]
+ temp_value = Packages(packages=packages)
+ logging.info(f"Packages Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Packages Validation Failed: {value}\nError: {e}"
+ )
+ try:
+ runners = [Runner(**item) for item in value]
+ temp_value = Runners(runners=runners)
+ logging.info(f"Runners Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n Runners Validation Failed: {value}\nError: {e}"
+ )
+ elif isinstance(value, dict):
+ for model_name, model in single_models.items():
+ try:
+ temp_value = model(**value)
+ logging.info(f"{model_name} Model Validation Success: {value}")
+ except Exception as e:
+ logging.warning(
+ f"\n\n\n {model_name} Dict Validation Failed for - {value}\nError: {e}"
+ )
+
+ value = temp_value
+ return value
diff --git a/gitlab_api/utils.py b/gitlab_api/utils.py
new file mode 100644
index 0000000..2183634
--- /dev/null
+++ b/gitlab_api/utils.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+# coding: utf-8
+import logging
+from typing import Union
+
+import requests
+
+try:
+ from gitlab_api.gitlab_models import (
+ Response,
+ )
+except ModuleNotFoundError:
+ from gitlab_models import (
+ Response,
+ )
+logging.basicConfig(
+ level=logging.ERROR, format="%(asctime)s - %(levelname)s - %(message)s"
+)
+
+
+def process_response(response: requests.Response) -> Union[Response, requests.Response]:
+ try:
+ response.raise_for_status()
+ except Exception as response_error:
+ logging.error(f"Response Error: {response_error}")
+ status_code = response.status_code
+ raw_output = response.content
+ try:
+ response = response.json()
+ except Exception as response_error:
+ logging.error(f"JSON Conversion Error: {response_error}")
+ try:
+ response = Response(
+ **response,
+ status_code=status_code,
+ raw_output=raw_output,
+ json_output=response,
+ )
+ except Exception as response_error:
+ logging.error(f"Response Model Application Error: {response_error}")
+
+ return response
diff --git a/gitlab_api/version.py b/gitlab_api/version.py
index 20966b0..2a1fc7d 100644
--- a/gitlab_api/version.py
+++ b/gitlab_api/version.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# coding: utf-8
-__version__ = '0.15.15'
-__author__ = 'Audel Rouhi'
-__credits__ = 'Audel Rouhi'
+__version__ = "0.15.15"
+__author__ = "Audel Rouhi"
+__credits__ = "Audel Rouhi"
diff --git a/requirements.txt b/requirements.txt
index b0456b3..61b0787 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,3 @@
requests>=2.28.1
urllib3>=1.26.13
-pydantic>=2.5.2
+pydantic[email]>=2.5.2
diff --git a/test/test_gitlab_models.py b/test/test_gitlab_models.py
index 3ce987c..d5b5fd9 100644
--- a/test/test_gitlab_models.py
+++ b/test/test_gitlab_models.py
@@ -1,3 +1,6 @@
+#!/usr/bin/python
+# coding: utf-8
+
import os
import sys
@@ -25,6 +28,7 @@
RunnerModel,
UserModel,
WikiModel,
+ Response,
)
except ImportError:
@@ -33,7 +37,6 @@
else:
skip = False
-
reason = "do not run on MacOS or windows OR dependency is not installed OR " + reason
@@ -195,6 +198,9092 @@ def test_wiki_model():
assert wiki.api_parameters == "?with_content=true"
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_project_response_1():
+ example_data = [
+ {
+ "id": 4,
+ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "description_html": '
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
',
+ "name": "Diaspora Client",
+ "name_with_namespace": "Diaspora / Diaspora Client",
+ "path": "diaspora-client",
+ "path_with_namespace": "diaspora/diaspora-client",
+ "created_at": "2013-09-30T13:46:02Z",
+ "updated_at": "2013-09-30T13:46:02Z",
+ "default_branch": "main",
+ "tag_list": ["example", "disapora client"],
+ "topics": ["example", "disapora client"],
+ "ssh_url_to_repo": "git@gitlab.example.com:diaspora/diaspora-client.git",
+ "http_url_to_repo": "https://gitlab.example.com/diaspora/diaspora-client.git",
+ "web_url": "https://gitlab.example.com/diaspora/diaspora-client",
+ "readme_url": "https://gitlab.example.com/diaspora/diaspora-client/blob/main/README.md",
+ "avatar_url": "https://gitlab.example.com/uploads/project/avatar/4/uploads/avatar.png",
+ "forks_count": 0,
+ "star_count": 0,
+ "last_activity_at": "2022-06-24T17:11:26.841Z",
+ "namespace": {
+ "id": 3,
+ "name": "Diaspora",
+ "path": "diaspora",
+ "kind": "group",
+ "full_path": "diaspora",
+ "parent_id": None,
+ "avatar_url": "https://gitlab.example.com/uploads/project/avatar/6/uploads/avatar.png",
+ "web_url": "https://gitlab.example.com/diaspora",
+ },
+ "container_registry_image_prefix": "registry.gitlab.example.com/diaspora/diaspora-client",
+ "_links": {
+ "self": "https://gitlab.example.com/api/v4/projects/4",
+ "issues": "https://gitlab.example.com/api/v4/projects/4/issues",
+ "merge_requests": "https://gitlab.example.com/api/v4/projects/4/merge_requests",
+ "repo_branches": "https://gitlab.example.com/api/v4/projects/4/repository/branches",
+ "labels": "https://gitlab.example.com/api/v4/projects/4/labels",
+ "events": "https://gitlab.example.com/api/v4/projects/4/events",
+ "members": "https://gitlab.example.com/api/v4/projects/4/members",
+ "cluster_agents": "https://gitlab.example.com/api/v4/projects/4/cluster_agents",
+ },
+ "packages_enabled": True,
+ "empty_repo": False,
+ "archived": False,
+ "visibility": "public",
+ "resolve_outdated_diff_discussions": False,
+ "container_expiration_policy": {
+ "cadence": "1month",
+ "enabled": True,
+ "keep_n": 1,
+ "older_than": "14d",
+ "name_regex": "",
+ "name_regex_keep": ".*-main",
+ "next_run_at": "2022-06-25T17:11:26.865Z",
+ },
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": True,
+ "container_registry_enabled": True,
+ "service_desk_enabled": True,
+ "can_create_merge_request_in": True,
+ "issues_access_level": "enabled",
+ "repository_access_level": "enabled",
+ "merge_requests_access_level": "enabled",
+ "forking_access_level": "enabled",
+ "wiki_access_level": "enabled",
+ "builds_access_level": "enabled",
+ "snippets_access_level": "enabled",
+ "pages_access_level": "enabled",
+ "analytics_access_level": "enabled",
+ "container_registry_access_level": "enabled",
+ "security_and_compliance_access_level": "private",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "shared_runners_enabled": True,
+ "group_runners_enabled": True,
+ "lfs_enabled": True,
+ "creator_id": 1,
+ "import_url": None,
+ "import_type": None,
+ "import_status": "none",
+ "import_error": None,
+ "open_issues_count": 0,
+ "ci_default_git_depth": 20,
+ "ci_forward_deployment_enabled": True,
+ "ci_forward_deployment_rollback_allowed": True,
+ "ci_allow_fork_pipelines_to_run_in_parent_project": True,
+ "ci_job_token_scope_enabled": False,
+ "ci_separated_caches": True,
+ "ci_restrict_pipeline_cancellation_role": "developer",
+ "public_jobs": True,
+ "build_timeout": 3600,
+ "auto_cancel_pending_pipelines": "enabled",
+ "ci_config_path": "",
+ "shared_with_groups": [],
+ "only_allow_merge_if_pipeline_succeeds": False,
+ "allow_merge_on_skipped_pipeline": None,
+ "restrict_user_defined_variables": False,
+ "request_access_enabled": True,
+ "only_allow_merge_if_all_discussions_are_resolved": False,
+ "remove_source_branch_after_merge": True,
+ "printing_merge_request_link_enabled": True,
+ "merge_method": "merge",
+ "squash_option": "default_off",
+ "enforce_auth_checks_on_uploads": True,
+ "suggestion_commit_message": None,
+ "merge_commit_template": None,
+ "squash_commit_template": None,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
+ "auto_devops_enabled": False,
+ "auto_devops_deploy_strategy": "continuous",
+ "autoclose_referenced_issues": True,
+ "keep_latest_artifact": True,
+ "runner_token_expiration_interval": None,
+ "external_authorization_classification_label": "",
+ "requirements_enabled": False,
+ "requirements_access_level": "enabled",
+ "security_and_compliance_enabled": False,
+ "compliance_frameworks": [],
+ "warn_about_potentially_unwanted_characters": True,
+ "permissions": {"project_access": None, "group_access": None},
+ },
+ {
+ "id": 4,
+ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "description_html": 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.
',
+ "default_branch": "main",
+ "visibility": "private",
+ "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
+ "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
+ "web_url": "http://example.com/diaspora/diaspora-client",
+ "readme_url": "http://example.com/diaspora/diaspora-client/blob/main/README.md",
+ "tag_list": ["example", "disapora client"],
+ "topics": ["example", "disapora client"],
+ "owner": {
+ "id": 3,
+ "name": "Diaspora",
+ "created_at": "2013-09-30T13:46:02Z",
+ },
+ "name": "Diaspora Client",
+ "name_with_namespace": "Diaspora / Diaspora Client",
+ "path": "diaspora-client",
+ "path_with_namespace": "diaspora/diaspora-client",
+ "issues_enabled": True,
+ "open_issues_count": 1,
+ "merge_requests_enabled": True,
+ "jobs_enabled": True,
+ "wiki_enabled": True,
+ "snippets_enabled": False,
+ "can_create_merge_request_in": True,
+ "resolve_outdated_diff_discussions": False,
+ "container_registry_enabled": False,
+ "container_registry_access_level": "disabled",
+ "security_and_compliance_access_level": "disabled",
+ "created_at": "2013-09-30T13:46:02Z",
+ "updated_at": "2013-09-30T13:46:02Z",
+ "last_activity_at": "2013-09-30T13:46:02Z",
+ "creator_id": 3,
+ "import_url": None,
+ "import_type": None,
+ "import_status": "none",
+ "import_error": None,
+ "namespace": {
+ "id": 3,
+ "name": "Diaspora",
+ "path": "diaspora",
+ "kind": "group",
+ "full_path": "diaspora",
+ },
+ "archived": False,
+ "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",
+ "shared_runners_enabled": True,
+ "group_runners_enabled": True,
+ "forks_count": 0,
+ "star_count": 0,
+ "runners_token": "b8547b1dc37721d05889db52fa2f02",
+ "ci_default_git_depth": 50,
+ "ci_forward_deployment_enabled": True,
+ "ci_forward_deployment_rollback_allowed": True,
+ "ci_allow_fork_pipelines_to_run_in_parent_project": True,
+ "ci_separated_caches": True,
+ "ci_restrict_pipeline_cancellation_role": "developer",
+ "public_jobs": True,
+ "shared_with_groups": [],
+ "only_allow_merge_if_pipeline_succeeds": False,
+ "allow_merge_on_skipped_pipeline": False,
+ "restrict_user_defined_variables": False,
+ "only_allow_merge_if_all_discussions_are_resolved": False,
+ "remove_source_branch_after_merge": False,
+ "request_access_enabled": False,
+ "merge_method": "merge",
+ "squash_option": "default_on",
+ "autoclose_referenced_issues": True,
+ "enforce_auth_checks_on_uploads": True,
+ "suggestion_commit_message": None,
+ "merge_commit_template": None,
+ "squash_commit_template": None,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
+ "marked_for_deletion_at": "2020-04-03",
+ "marked_for_deletion_on": "2020-04-03",
+ "statistics": {
+ "commit_count": 37,
+ "storage_size": 1038090,
+ "repository_size": 1038090,
+ "wiki_size": 0,
+ "lfs_objects_size": 0,
+ "job_artifacts_size": 0,
+ "pipeline_artifacts_size": 0,
+ "packages_size": 0,
+ "snippets_size": 0,
+ "uploads_size": 0,
+ },
+ "container_registry_image_prefix": "registry.example.com/diaspora/diaspora-client",
+ "_links": {
+ "self": "http://example.com/api/v4/projects",
+ "issues": "http://example.com/api/v4/projects/1/issues",
+ "merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
+ "repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
+ "labels": "http://example.com/api/v4/projects/1/labels",
+ "events": "http://example.com/api/v4/projects/1/events",
+ "members": "http://example.com/api/v4/projects/1/members",
+ "cluster_agents": "http://example.com/api/v4/projects/1/cluster_agents",
+ },
+ },
+ {
+ "id": 6,
+ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "description_html": 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.
',
+ "default_branch": "main",
+ "visibility": "private",
+ "ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
+ "http_url_to_repo": "http://example.com/brightbox/puppet.git",
+ "web_url": "http://example.com/brightbox/puppet",
+ "readme_url": "http://example.com/brightbox/puppet/blob/main/README.md",
+ "tag_list": ["example", "puppet"],
+ "topics": ["example", "puppet"],
+ "owner": {
+ "id": 4,
+ "name": "Brightbox",
+ "created_at": "2013-09-30T13:46:02Z",
+ },
+ "name": "Puppet",
+ "name_with_namespace": "Brightbox / Puppet",
+ "path": "puppet",
+ "path_with_namespace": "brightbox/puppet",
+ "issues_enabled": True,
+ "open_issues_count": 1,
+ "merge_requests_enabled": True,
+ "jobs_enabled": True,
+ "wiki_enabled": True,
+ "snippets_enabled": False,
+ "can_create_merge_request_in": True,
+ "resolve_outdated_diff_discussions": False,
+ "container_registry_enabled": False,
+ "container_registry_access_level": "disabled",
+ "security_and_compliance_access_level": "disabled",
+ "created_at": "2013-09-30T13:46:02Z",
+ "updated_at": "2013-09-30T13:46:02Z",
+ "last_activity_at": "2013-09-30T13:46:02Z",
+ "creator_id": 3,
+ "import_url": None,
+ "import_type": None,
+ "namespace": {
+ "id": 4,
+ "name": "Brightbox",
+ "path": "brightbox",
+ "kind": "group",
+ "full_path": "brightbox",
+ },
+ "import_status": "none",
+ "import_error": None,
+ "permissions": {
+ "project_access": {"access_level": 10, "notification_level": 3},
+ "group_access": {"access_level": 50, "notification_level": 3},
+ },
+ "archived": False,
+ "avatar_url": None,
+ "shared_runners_enabled": True,
+ "group_runners_enabled": True,
+ "forks_count": 0,
+ "star_count": 0,
+ "runners_token": "b8547b1dc37721d05889db52fa2f02",
+ "ci_default_git_depth": 0,
+ "ci_forward_deployment_enabled": True,
+ "ci_forward_deployment_rollback_allowed": True,
+ "ci_allow_fork_pipelines_to_run_in_parent_project": True,
+ "ci_separated_caches": True,
+ "ci_restrict_pipeline_cancellation_role": "developer",
+ "public_jobs": True,
+ "shared_with_groups": [],
+ "only_allow_merge_if_pipeline_succeeds": False,
+ "allow_merge_on_skipped_pipeline": False,
+ "restrict_user_defined_variables": False,
+ "only_allow_merge_if_all_discussions_are_resolved": False,
+ "remove_source_branch_after_merge": False,
+ "request_access_enabled": False,
+ "merge_method": "merge",
+ "squash_option": "default_on",
+ "auto_devops_enabled": True,
+ "auto_devops_deploy_strategy": "continuous",
+ "repository_storage": "default",
+ "approvals_before_merge": 0,
+ "mirror": False,
+ "mirror_user_id": 45,
+ "mirror_trigger_builds": False,
+ "only_mirror_protected_branches": False,
+ "mirror_overwrites_diverged_branches": False,
+ "external_authorization_classification_label": None,
+ "packages_enabled": True,
+ "service_desk_enabled": False,
+ "service_desk_address": None,
+ "autoclose_referenced_issues": True,
+ "enforce_auth_checks_on_uploads": True,
+ "suggestion_commit_message": None,
+ "merge_commit_template": None,
+ "squash_commit_template": None,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
+ "statistics": {
+ "commit_count": 12,
+ "storage_size": 2066080,
+ "repository_size": 2066080,
+ "wiki_size": 0,
+ "lfs_objects_size": 0,
+ "job_artifacts_size": 0,
+ "pipeline_artifacts_size": 0,
+ "packages_size": 0,
+ "snippets_size": 0,
+ "uploads_size": 0,
+ },
+ "container_registry_image_prefix": "registry.example.com/brightbox/puppet",
+ "_links": {
+ "self": "http://example.com/api/v4/projects",
+ "issues": "http://example.com/api/v4/projects/1/issues",
+ "merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
+ "repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
+ "labels": "http://example.com/api/v4/projects/1/labels",
+ "events": "http://example.com/api/v4/projects/1/events",
+ "members": "http://example.com/api/v4/projects/1/members",
+ "cluster_agents": "http://example.com/api/v4/projects/1/cluster_agents",
+ },
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Projects"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_project_response_2():
+ example_data = {
+ "id": 4,
+ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ "description_html": 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.
',
+ "name": "Diaspora Client",
+ "name_with_namespace": "Diaspora / Diaspora Client",
+ "path": "diaspora-client",
+ "path_with_namespace": "diaspora/diaspora-client",
+ "created_at": "2013-09-30T13:46:02Z",
+ "updated_at": "2013-09-30T13:46:02Z",
+ "default_branch": "main",
+ "tag_list": ["example", "disapora client"],
+ "topics": ["example", "disapora client"],
+ "ssh_url_to_repo": "git@gitlab.example.com:diaspora/diaspora-client.git",
+ "http_url_to_repo": "https://gitlab.example.com/diaspora/diaspora-client.git",
+ "web_url": "https://gitlab.example.com/diaspora/diaspora-client",
+ "readme_url": "https://gitlab.example.com/diaspora/diaspora-client/blob/main/README.md",
+ "avatar_url": "https://gitlab.example.com/uploads/project/avatar/4/uploads/avatar.png",
+ "forks_count": 0,
+ "star_count": 0,
+ "last_activity_at": "2022-06-24T17:11:26.841Z",
+ "namespace": {
+ "id": 3,
+ "name": "Diaspora",
+ "path": "diaspora",
+ "kind": "group",
+ "full_path": "diaspora",
+ "parent_id": None,
+ "avatar_url": "https://gitlab.example.com/uploads/project/avatar/6/uploads/avatar.png",
+ "web_url": "https://gitlab.example.com/diaspora",
+ },
+ "container_registry_image_prefix": "registry.gitlab.example.com/diaspora/diaspora-client",
+ "_links": {
+ "self": "https://gitlab.example.com/api/v4/projects/4",
+ "issues": "https://gitlab.example.com/api/v4/projects/4/issues",
+ "merge_requests": "https://gitlab.example.com/api/v4/projects/4/merge_requests",
+ "repo_branches": "https://gitlab.example.com/api/v4/projects/4/repository/branches",
+ "labels": "https://gitlab.example.com/api/v4/projects/4/labels",
+ "events": "https://gitlab.example.com/api/v4/projects/4/events",
+ "members": "https://gitlab.example.com/api/v4/projects/4/members",
+ "cluster_agents": "https://gitlab.example.com/api/v4/projects/4/cluster_agents",
+ },
+ "packages_enabled": True,
+ "empty_repo": False,
+ "archived": False,
+ "visibility": "public",
+ "resolve_outdated_diff_discussions": False,
+ "container_expiration_policy": {
+ "cadence": "1month",
+ "enabled": True,
+ "keep_n": 1,
+ "older_than": "14d",
+ "name_regex": "",
+ "name_regex_keep": ".*-main",
+ "next_run_at": "2022-06-25T17:11:26.865Z",
+ },
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": True,
+ "container_registry_enabled": True,
+ "service_desk_enabled": True,
+ "can_create_merge_request_in": True,
+ "issues_access_level": "enabled",
+ "repository_access_level": "enabled",
+ "merge_requests_access_level": "enabled",
+ "forking_access_level": "enabled",
+ "wiki_access_level": "enabled",
+ "builds_access_level": "enabled",
+ "snippets_access_level": "enabled",
+ "pages_access_level": "enabled",
+ "analytics_access_level": "enabled",
+ "container_registry_access_level": "enabled",
+ "security_and_compliance_access_level": "private",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "shared_runners_enabled": True,
+ "group_runners_enabled": True,
+ "lfs_enabled": True,
+ "creator_id": 1,
+ "import_url": None,
+ "import_type": None,
+ "import_status": "none",
+ "import_error": None,
+ "open_issues_count": 0,
+ "ci_default_git_depth": 20,
+ "ci_forward_deployment_enabled": True,
+ "ci_forward_deployment_rollback_allowed": True,
+ "ci_allow_fork_pipelines_to_run_in_parent_project": True,
+ "ci_job_token_scope_enabled": False,
+ "ci_separated_caches": True,
+ "ci_restrict_pipeline_cancellation_role": "developer",
+ "public_jobs": True,
+ "build_timeout": 3600,
+ "auto_cancel_pending_pipelines": "enabled",
+ "ci_config_path": "",
+ "shared_with_groups": [],
+ "only_allow_merge_if_pipeline_succeeds": False,
+ "allow_merge_on_skipped_pipeline": None,
+ "restrict_user_defined_variables": False,
+ "request_access_enabled": True,
+ "only_allow_merge_if_all_discussions_are_resolved": False,
+ "remove_source_branch_after_merge": True,
+ "printing_merge_request_link_enabled": True,
+ "merge_method": "merge",
+ "squash_option": "default_off",
+ "enforce_auth_checks_on_uploads": True,
+ "suggestion_commit_message": None,
+ "merge_commit_template": None,
+ "squash_commit_template": None,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
+ "auto_devops_enabled": False,
+ "auto_devops_deploy_strategy": "continuous",
+ "autoclose_referenced_issues": True,
+ "keep_latest_artifact": True,
+ "runner_token_expiration_interval": None,
+ "external_authorization_classification_label": "",
+ "requirements_enabled": False,
+ "requirements_access_level": "enabled",
+ "security_and_compliance_enabled": False,
+ "compliance_frameworks": [],
+ "warn_about_potentially_unwanted_characters": True,
+ "permissions": {"project_access": None, "group_access": None},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Project"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_user_response_1():
+ example_data = [
+ {
+ "id": 1,
+ "username": "john_smith",
+ "name": "John Smith",
+ "state": "active",
+ "locked": False,
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
+ "web_url": "http://localhost:3000/john_smith",
+ },
+ {
+ "id": 2,
+ "username": "jack_smith",
+ "name": "Jack Smith",
+ "state": "blocked",
+ "locked": False,
+ "avatar_url": "http://gravatar.com/../e32131cd8.jpeg",
+ "web_url": "http://localhost:3000/jack_smith",
+ },
+ {
+ "id": 4,
+ "username": "john_smith",
+ "email": "john@example.com",
+ "name": "John Smith",
+ "state": "active",
+ "locked": False,
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/1/index.jpg",
+ "web_url": "http://localhost:3000/john_smith",
+ "created_at": "2012-05-23T08:00:58Z",
+ "is_admin": False,
+ "bio": "",
+ "location": None,
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "discord": "",
+ "website_url": "",
+ "organization": "",
+ "job_title": "",
+ "last_sign_in_at": "2012-06-01T11:41:01Z",
+ "confirmed_at": "2012-05-23T09:05:22Z",
+ "theme_id": 1,
+ "last_activity_on": "2012-05-23",
+ "color_scheme_id": 2,
+ "projects_limit": 100,
+ "current_sign_in_at": "2012-06-02T06:36:55Z",
+ "note": "DMCA Request: 2018-11-05 | DMCA Violation | Abuse | https://gitlab.zendesk.com/agent/tickets/123",
+ "identities": [
+ {"provider": "github", "extern_uid": "2435223452345"},
+ {"provider": "bitbucket", "extern_uid": "john.smith"},
+ {
+ "provider": "google_oauth2",
+ "extern_uid": "8776128412476123468721346",
+ },
+ ],
+ "can_create_group": True,
+ "can_create_project": True,
+ "two_factor_enabled": True,
+ "external": False,
+ "private_profile": False,
+ "current_sign_in_ip": "196.165.1.102",
+ "last_sign_in_ip": "172.127.2.22",
+ "namespace_id": 1,
+ "created_by": None,
+ "email_reset_offered_at": None,
+ },
+ {
+ "id": 3,
+ "username": "jack_smith",
+ "email": "jack@example.com",
+ "name": "Jack Smith",
+ "state": "blocked",
+ "locked": False,
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/2/index.jpg",
+ "web_url": "http://localhost:3000/jack_smith",
+ "created_at": "2012-05-23T08:01:01Z",
+ "is_admin": False,
+ "bio": "",
+ "location": None,
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "discord": "",
+ "website_url": "",
+ "organization": "",
+ "job_title": "",
+ "last_sign_in_at": None,
+ "confirmed_at": "2012-05-30T16:53:06.148Z",
+ "theme_id": 1,
+ "last_activity_on": "2012-05-23",
+ "color_scheme_id": 3,
+ "projects_limit": 100,
+ "current_sign_in_at": "2014-03-19T17:54:13Z",
+ "identities": [],
+ "can_create_group": True,
+ "can_create_project": True,
+ "two_factor_enabled": True,
+ "external": False,
+ "private_profile": False,
+ "current_sign_in_ip": "10.165.1.102",
+ "last_sign_in_ip": "172.127.2.22",
+ "namespace_id": 2,
+ "created_by": None,
+ "email_reset_offered_at": None,
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_user_response_2():
+ example_data = {
+ "id": 1,
+ "username": "john_smith",
+ "name": "John Smith",
+ "state": "active",
+ "locked": False,
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
+ "web_url": "http://localhost:3000/john_smith",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "User"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_branch_response_1():
+ example_data = [
+ {
+ "name": "main",
+ "merged": False,
+ "protected": True,
+ "default": True,
+ "developers_can_push": False,
+ "developers_can_merge": False,
+ "can_push": True,
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/tree/main",
+ "commit": {
+ "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ "short_id": "7b5c3cc",
+ "created_at": "2012-06-28T03:44:20-07:00",
+ "parent_ids": ["4ad91d3c1144c406e50c7b33bae684bd6837faf8"],
+ "title": "add projects API",
+ "message": "add projects API",
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committer_name": "John Smith",
+ "committer_email": "john@example.com",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "trailers": {},
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ },
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Branches"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_branch_response_2():
+ example_data = {
+ "name": "main",
+ "merged": False,
+ "protected": True,
+ "default": True,
+ "developers_can_push": False,
+ "developers_can_merge": False,
+ "can_push": True,
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/tree/main",
+ "commit": {
+ "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ "short_id": "7b5c3cc",
+ "created_at": "2012-06-28T03:44:20-07:00",
+ "parent_ids": ["4ad91d3c1144c406e50c7b33bae684bd6837faf8"],
+ "title": "add projects API",
+ "message": "add projects API",
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committer_name": "John Smith",
+ "committer_email": "john@example.com",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "trailers": {},
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Branch"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_branch_response_3():
+ example_data = [
+ {
+ "name": "main",
+ "merged": False,
+ "protected": True,
+ "default": True,
+ "developers_can_push": False,
+ "developers_can_merge": False,
+ "can_push": True,
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/tree/main",
+ "commit": {
+ "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ "short_id": "7b5c3cc",
+ "created_at": "2012-06-28T03:44:20-07:00",
+ "parent_ids": ["4ad91d3c1144c406e50c7b33bae684bd6837faf8"],
+ "title": "add projects API",
+ "message": "add projects API",
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committer_name": "John Smith",
+ "committer_email": "john@example.com",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "trailers": {},
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ },
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Branches"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_branch_response_4():
+ example_data = {
+ "commit": {
+ "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ "short_id": "7b5c3cc",
+ "created_at": "2012-06-28T03:44:20-07:00",
+ "parent_ids": ["4ad91d3c1144c406e50c7b33bae684bd6837faf8"],
+ "title": "add projects API",
+ "message": "add projects API",
+ "author_name": "Bob Smith",
+ "author_email": "bob@example.com",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committer_name": "Susan Smith",
+ "committer_email": "susan@example.com",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "trailers": {},
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ },
+ "name": "newbranch",
+ "merged": False,
+ "protected": False,
+ "default": False,
+ "developers_can_push": False,
+ "developers_can_merge": False,
+ "can_push": True,
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/tree/newbranch",
+ }
+
+ print(f"EXAMPLE DATA: {example_data}")
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Branch"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_1():
+ example_data = [
+ {
+ "id": "ed899a2f4b50b4370feeea94676502b42383c746",
+ "short_id": "ed899a2f4b5",
+ "title": "Replace sanitize with escape once",
+ "author_name": "Example User",
+ "author_email": "user@example.com",
+ "authored_date": "2021-09-20T11:50:22.001+00:00",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2021-09-20T11:50:22.001+00:00",
+ "created_at": "2021-09-20T11:50:22.001+00:00",
+ "message": "Replace sanitize with escape once",
+ "parent_ids": ["6104942438c14ec7bd21c6cd5bd995272b3faff6"],
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746",
+ "trailers": {},
+ "extended_trailers": {},
+ },
+ {
+ "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
+ "short_id": "6104942438c",
+ "title": "Sanitize for network graph",
+ "author_name": "randx",
+ "author_email": "user@example.com",
+ "committer_name": "ExampleName",
+ "committer_email": "user@example.com",
+ "created_at": "2021-09-20T09:06:12.201+00:00",
+ "message": "Sanitize for network graph\nCc: John Doe \nCc: Jane Doe ",
+ "parent_ids": ["ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"],
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746",
+ "trailers": {"Cc": "Jane Doe "},
+ "extended_trailers": {
+ "Cc": ["John Doe ", "Jane Doe "]
+ },
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commits"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_2():
+ example_data = {
+ "id": "ed899a2f4b50b4370feeea94676502b42383c746",
+ "short_id": "ed899a2f4b5",
+ "title": "some commit message",
+ "author_name": "Example User",
+ "author_email": "user@example.com",
+ "committer_name": "Example User",
+ "committer_email": "user@example.com",
+ "created_at": "2016-09-20T09:26:24.000-07:00",
+ "message": "some commit message",
+ "parent_ids": ["ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"],
+ "committed_date": "2016-09-20T09:26:24.000-07:00",
+ "authored_date": "2016-09-20T09:26:24.000-07:00",
+ "stats": {"additions": 2, "deletions": 2, "total": 4},
+ "status": None,
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_3():
+ example_data = {
+ "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
+ "short_id": "6104942438c",
+ "title": "Sanitize for network graph",
+ "author_name": "randx",
+ "author_email": "user@example.com",
+ "committer_name": "Dmitriy",
+ "committer_email": "user@example.com",
+ "created_at": "2021-09-20T09:06:12.300+03:00",
+ "message": "Sanitize for network graph",
+ "committed_date": "2021-09-20T09:06:12.300+03:00",
+ "authored_date": "2021-09-20T09:06:12.420+03:00",
+ "parent_ids": ["ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"],
+ "last_pipeline": {
+ "id": 8,
+ "ref": "main",
+ "sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0",
+ "status": "created",
+ },
+ "stats": {"additions": 15, "deletions": 10, "total": 25},
+ "status": "running",
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/6104942438c14ec7bd21c6cd5bd995272b3faff6",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_4():
+ example_data = {"count": 632}
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_5():
+ example_data = {
+ "id": "8b090c1b79a14f2bd9e8a738f717824ff53aebad",
+ "short_id": "8b090c1b",
+ "author_name": "Example User",
+ "author_email": "user@example.com",
+ "authored_date": "2016-12-12T20:10:39.000+01:00",
+ "created_at": "2016-12-12T20:10:39.000+01:00",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2016-12-12T20:10:39.000+01:00",
+ "title": "Feature added",
+ "message": "Feature added\n\nSigned-off-by: Example User \n",
+ "parent_ids": ["a738f717824ff53aebad8b090c1b79a14f2bd9e8"],
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/8b090c1b79a14f2bd9e8a738f717824ff53aebad",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_6():
+ example_data = {
+ "id": "8b090c1b79a14f2bd9e8a738f717824ff53aebad",
+ "short_id": "8b090c1b",
+ "title": 'Revert "Feature added"',
+ "created_at": "2018-11-08T15:55:26.000Z",
+ "parent_ids": ["a738f717824ff53aebad8b090c1b79a14f2bd9e8"],
+ "message": 'Revert "Feature added"\n\nThis reverts commit a738f717824ff53aebad8b090c1b79a14f2bd9e8',
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2018-11-08T15:55:26.000Z",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2018-11-08T15:55:26.000Z",
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/8b090c1b79a14f2bd9e8a738f717824ff53aebad",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_7():
+ example_data = {
+ "message": "Sorry, we cannot revert this commit automatically. This commit may already have been reverted, or a more recent commit may have updated some of its content.",
+ "error_code": "conflict",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_8():
+ example_data = {"dry_run": "success"}
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_9():
+ example_data = [
+ {
+ "diff": "@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
+ "new_path": "doc/update/5.4-to-6.0.md",
+ "old_path": "doc/update/5.4-to-6.0.md",
+ "a_mode": None,
+ "b_mode": "100644",
+ "new_file": False,
+ "renamed_file": False,
+ "deleted_file": False,
+ }
+ ]
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Diffs"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_10():
+ example_data = [
+ {
+ "note": "this code is really nice",
+ "author": {
+ "id": 11,
+ "username": "admin",
+ "email": "admin@local.host",
+ "name": "Administrator",
+ "state": "active",
+ "created_at": "2014-03-06T08:17:35.000Z",
+ },
+ }
+ ]
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Comments"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_11():
+ example_data = {
+ "author": {
+ "web_url": "https://gitlab.example.com/janedoe",
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ "username": "janedoe",
+ "state": "active",
+ "name": "Jane Doe",
+ "id": 28,
+ },
+ "created_at": "2016-01-19T09:44:55.600Z",
+ "line_type": "new",
+ "path": "README.md",
+ "line": 11,
+ "note": "Nice picture!",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Comment"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_12():
+ example_data = [
+ {
+ "id": "4604744a1c64de00ff62e1e8a6766919923d2b41",
+ "individual_note": True,
+ "notes": [
+ {
+ "id": 334686748,
+ "type": None,
+ "body": "Nice piece of code!",
+ "attachment": None,
+ "author": {
+ "id": 28,
+ "name": "Jane Doe",
+ "username": "janedoe",
+ "web_url": "https://gitlab.example.com/janedoe",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ },
+ "created_at": "2020-04-30T18:48:11.432Z",
+ "updated_at": "2020-04-30T18:48:11.432Z",
+ "system": False,
+ "noteable_id": None,
+ "noteable_type": "Commit",
+ "resolvable": False,
+ "confidential": None,
+ "noteable_iid": None,
+ "commands_changes": {},
+ }
+ ],
+ }
+ ]
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commits"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_13():
+ example_data = [
+ {
+ "status": "pending",
+ "created_at": "2016-01-19T08:40:25.934Z",
+ "started_at": None,
+ "name": "bundler:audit",
+ "allow_failure": True,
+ "author": {
+ "username": "janedoe",
+ "state": "active",
+ "web_url": "https://gitlab.example.com/janedoe",
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ "id": 28,
+ "name": "Jane Doe",
+ },
+ "description": None,
+ "sha": "18f3e63d05582537db6d183d9d557be09e1f90c8",
+ "target_url": "https://gitlab.example.com/janedoe/gitlab-foss/builds/91",
+ "finished_at": None,
+ "id": 91,
+ "ref": "main",
+ },
+ {
+ "started_at": None,
+ "name": "test",
+ "allow_failure": False,
+ "status": "pending",
+ "created_at": "2016-01-19T08:40:25.832Z",
+ "target_url": "https://gitlab.example.com/janedoe/gitlab-foss/builds/90",
+ "id": 90,
+ "finished_at": None,
+ "ref": "main",
+ "sha": "18f3e63d05582537db6d183d9d557be09e1f90c8",
+ "author": {
+ "id": 28,
+ "name": "Jane Doe",
+ "username": "janedoe",
+ "web_url": "https://gitlab.example.com/janedoe",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ },
+ "description": None,
+ },
+ ]
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commits"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_14():
+ example_data = {
+ "author": {
+ "web_url": "https://gitlab.example.com/janedoe",
+ "name": "Jane Doe",
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ "username": "janedoe",
+ "state": "active",
+ "id": 28,
+ },
+ "name": "default",
+ "sha": "18f3e63d05582537db6d183d9d557be09e1f90c8",
+ "status": "success",
+ "coverage": 100.0,
+ "description": None,
+ "id": 93,
+ "target_url": None,
+ "ref": None,
+ "started_at": None,
+ "created_at": "2016-01-19T09:05:50.355Z",
+ "allow_failure": False,
+ "finished_at": "2016-01-19T09:05:50.365Z",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commit"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_15():
+ example_data = [
+ {
+ "id": 45,
+ "iid": 1,
+ "project_id": 35,
+ "title": "Add new file",
+ "description": "",
+ "state": "opened",
+ "created_at": "2018-03-26T17:26:30.916Z",
+ "updated_at": "2018-03-26T17:26:30.916Z",
+ "target_branch": "main",
+ "source_branch": "test-branch",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "web_url": "https://gitlab.example.com/janedoe",
+ "name": "Jane Doe",
+ "avatar_url": "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ "username": "janedoe",
+ "state": "active",
+ "id": 28,
+ },
+ "assignee": None,
+ "source_project_id": 35,
+ "target_project_id": 35,
+ "labels": [],
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": None,
+ "merge_when_pipeline_succeeds": False,
+ "merge_status": "can_be_merged",
+ "sha": "af5b13261899fb2c0db30abdd0af8b07cb44fdc5",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 0,
+ "discussion_locked": None,
+ "should_remove_source_branch": None,
+ "force_remove_source_branch": False,
+ "web_url": "https://gitlab.example.com/root/test-project/merge_requests/1",
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ }
+ ]
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequests"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_16():
+ example_data = {
+ "signature_type": "PGP",
+ "verification_status": "verified",
+ "gpg_key_id": 1,
+ "gpg_key_primary_keyid": "8254AAB3FBD54AC9",
+ "gpg_key_user_name": "John Doe",
+ "gpg_key_user_email": "johndoe@example.com",
+ "gpg_key_subkey_id": None,
+ "commit_source": "gitaly",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "CommitSignature"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_17():
+ example_data = {
+ "signature_type": "SSH",
+ "verification_status": "verified",
+ "key": {
+ "id": 11,
+ "title": "Key",
+ "created_at": "2023-05-08T09:12:38.503Z",
+ "expires_at": "2024-05-07T00:00:00.000Z",
+ "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILZzYDq6DhLp3aX84DGIV3F6Vf+Ae4yCTTz7RnqMJOlR MyKey)",
+ "usage_type": "auth_and_signing",
+ },
+ "commit_source": "gitaly",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "CommitSignature"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_18():
+ example_data = {
+ "signature_type": "X509",
+ "verification_status": "unverified",
+ "x509_certificate": {
+ "id": 1,
+ "subject": "CN=gitlab@example.org,OU=Example,O=World",
+ "subject_key_identifier": "BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC",
+ "email": "gitlab@example.org",
+ "serial_number": 278969561018901340486471282831158785578,
+ "certificate_status": "good",
+ "x509_issuer": {
+ "id": 1,
+ "subject": "CN=PKI,OU=Example,O=World",
+ "subject_key_identifier": "AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB",
+ "crl_url": "http://example.com/pki.crl",
+ },
+ },
+ "commit_source": "gitaly",
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "CommitSignature"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_commit_response_19():
+ example_data = {"message": "404 GPG Signature Not Found"}
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "CommitSignature"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_deploy_token_response_1():
+ example_data = [
+ {
+ "id": 1,
+ "name": "MyToken",
+ "username": "gitlab+deploy-token-1",
+ "expires_at": "2020-02-14T00:00:00.000Z",
+ "revoked": False,
+ "expired": False,
+ "scopes": ["read_repository", "read_registry"],
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployTokens"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_deploy_token_response_1():
+ example_data = [
+ {
+ "id": 1,
+ "name": "MyToken",
+ "username": "gitlab+deploy-token-1",
+ "expires_at": "2020-02-14T00:00:00.000Z",
+ "revoked": False,
+ "expired": False,
+ "scopes": ["read_repository", "read_registry"],
+ }
+ ]
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployTokens"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_deploy_token_response_2():
+ example_data = {
+ "id": 1,
+ "name": "MyToken",
+ "username": "gitlab+deploy-token-1",
+ "expires_at": "2020-02-14T00:00:00.000Z",
+ "revoked": False,
+ "expired": False,
+ "scopes": ["read_repository", "read_registry"],
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployToken"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_deploy_token_response_3():
+ example_data = {
+ "id": 1,
+ "name": "My deploy token",
+ "username": "custom-user",
+ "expires_at": "2021-01-01T00:00:00.000Z",
+ "token": "jMRvtPNxrn3crTAGukpZ",
+ "revoked": False,
+ "expired": False,
+ "scopes": ["read_repository"],
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployToken"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_deploy_token_response_4():
+ example_data = [
+ {
+ "id": 1,
+ "name": "MyToken",
+ "username": "gitlab+deploy-token-1",
+ "expires_at": "2020-02-14T00:00:00.000Z",
+ "revoked": False,
+ "expired": False,
+ "scopes": ["read_repository", "read_registry"],
+ }
+ ]
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployTokens"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_deploy_token_response_5():
+ example_data = {
+ "id": 1,
+ "name": "MyToken",
+ "username": "gitlab+deploy-token-1",
+ "expires_at": "2020-02-14T00:00:00.000Z",
+ "revoked": False,
+ "expired": False,
+ "scopes": ["read_repository", "read_registry"],
+ }
+
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployToken"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_1():
+ example_data = [
+ {
+ "id": 1,
+ "iid": 1,
+ "project_id": 3,
+ "title": "test1",
+ "description": "fixed login page css paddings",
+ "state": "merged",
+ "imported": False,
+ "imported_from": "none",
+ "merged_by": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merge_user": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merged_at": "2018-09-07T11:16:17.520Z",
+ "prepared_at": "2018-09-04T11:16:17.520Z",
+ "closed_by": None,
+ "closed_at": None,
+ "created_at": "2017-04-29T08:46:00Z",
+ "updated_at": "2017-04-29T08:46:00Z",
+ "target_branch": "main",
+ "source_branch": "test1",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignee": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "reviewers": [
+ {
+ "id": 2,
+ "name": "Sam Bauch",
+ "username": "kenyatta_oconnell",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon",
+ "web_url": "http://gitlab.example.com//kenyatta_oconnell",
+ }
+ ],
+ "source_project_id": 2,
+ "target_project_id": 3,
+ "labels": ["Community contribution", "Manage"],
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": "2018-09-22",
+ "start_date": "2018-08-08",
+ "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1",
+ },
+ "merge_when_pipeline_succeeds": True,
+ "merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
+ "sha": "8888888888888888888888888888888888888888",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 1,
+ "discussion_locked": None,
+ "should_remove_source_branch": True,
+ "force_remove_source_branch": False,
+ "allow_collaboration": False,
+ "allow_maintainer_to_push": False,
+ "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
+ "references": {
+ "short": "!1",
+ "relative": "my-group/my-project!1",
+ "full": "my-group/my-project!1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "squash": False,
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequests"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_2():
+ example_data = [
+ {
+ "id": 1,
+ "iid": 1,
+ "project_id": 3,
+ "title": "test1",
+ "description": "fixed login page css paddings",
+ "state": "merged",
+ "imported": False,
+ "imported_from": "none",
+ "merged_by": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "locked": False,
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merge_user": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "locked": False,
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merged_at": "2018-09-07T11:16:17.520Z",
+ "prepared_at": "2018-09-04T11:16:17.520Z",
+ "closed_by": None,
+ "closed_at": None,
+ "created_at": "2017-04-29T08:46:00Z",
+ "updated_at": "2017-04-29T08:46:00Z",
+ "target_branch": "main",
+ "source_branch": "test1",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "locked": False,
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignee": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "locked": False,
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "locked": False,
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "reviewers": [
+ {
+ "id": 2,
+ "name": "Sam Bauch",
+ "username": "kenyatta_oconnell",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon",
+ "web_url": "http://gitlab.example.com//kenyatta_oconnell",
+ }
+ ],
+ "source_project_id": 2,
+ "target_project_id": 3,
+ "labels": ["Community contribution", "Manage"],
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": "2018-09-22",
+ "start_date": "2018-08-08",
+ "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1",
+ },
+ "merge_when_pipeline_succeeds": True,
+ "merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
+ "sha": "8888888888888888888888888888888888888888",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 1,
+ "discussion_locked": None,
+ "should_remove_source_branch": True,
+ "force_remove_source_branch": False,
+ "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
+ "reference": "!1",
+ "references": {
+ "short": "!1",
+ "relative": "!1",
+ "full": "my-group/my-project!1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "squash": False,
+ "squash_on_merge": False,
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ "has_conflicts": False,
+ "blocking_discussions_resolved": True,
+ "approvals_before_merge": 2,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequests"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_3():
+ example_data = [
+ {
+ "id": 1,
+ "iid": 1,
+ "project_id": 3,
+ "title": "test1",
+ "description": "fixed login page css paddings",
+ "state": "merged",
+ "imported": False,
+ "imported_from": "none",
+ "merged_by": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merge_user": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merged_at": "2018-09-07T11:16:17.520Z",
+ "prepared_at": "2018-09-04T11:16:17.520Z",
+ "closed_by": None,
+ "closed_at": None,
+ "created_at": "2017-04-29T08:46:00Z",
+ "updated_at": "2017-04-29T08:46:00Z",
+ "target_branch": "main",
+ "source_branch": "test1",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignee": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "reviewers": [
+ {
+ "id": 2,
+ "name": "Sam Bauch",
+ "username": "kenyatta_oconnell",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon",
+ "web_url": "http://gitlab.example.com//kenyatta_oconnell",
+ }
+ ],
+ "source_project_id": 2,
+ "target_project_id": 3,
+ "labels": ["Community contribution", "Manage"],
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": "2018-10-22",
+ "start_date": "2018-09-08",
+ "web_url": "gitlab.example.com/my-group/my-project/milestones/1",
+ },
+ "merge_when_pipeline_succeeds": True,
+ "merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
+ "sha": "8888888888888888888888888888888888888888",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 1,
+ "discussion_locked": None,
+ "should_remove_source_branch": True,
+ "force_remove_source_branch": False,
+ "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
+ "references": {
+ "short": "!1",
+ "relative": "my-project!1",
+ "full": "my-group/my-project!1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "squash": False,
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ "has_conflicts": False,
+ "blocking_discussions_resolved": True,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequests"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_4():
+ # Users Model
+ example_data = [
+ {
+ "id": 1,
+ "name": "John Doe1",
+ "username": "user1",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
+ "web_url": "http://localhost/user1",
+ },
+ {
+ "id": 2,
+ "name": "John Doe2",
+ "username": "user2",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon",
+ "web_url": "http://localhost/user2",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_5():
+ # Reviewers
+ example_data = [
+ {
+ "user": {
+ "id": 1,
+ "name": "John Doe1",
+ "username": "user1",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
+ "web_url": "http://localhost/user1",
+ },
+ "state": "unreviewed",
+ "created_at": "2022-07-27T17:03:27.684Z",
+ },
+ {
+ "user": {
+ "id": 2,
+ "name": "John Doe2",
+ "username": "user2",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon",
+ "web_url": "http://localhost/user2",
+ },
+ "state": "reviewed",
+ "created_at": "2022-07-27T17:03:27.684Z",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequests"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_6():
+ # Commits
+ example_data = [
+ {
+ "id": "ed899a2f4b50b4370feeea94676502b42383c746",
+ "short_id": "ed899a2f4b5",
+ "title": "Replace sanitize with escape once",
+ "author_name": "Example User",
+ "author_email": "user@example.com",
+ "created_at": "2012-09-20T11:50:22+03:00",
+ "message": "Replace sanitize with escape once",
+ },
+ {
+ "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
+ "short_id": "6104942438c",
+ "title": "Sanitize for network graph",
+ "author_name": "Example User",
+ "author_email": "user@example.com",
+ "created_at": "2012-09-20T09:06:12+03:00",
+ "message": "Sanitize for network graph",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Commits"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_7():
+ # Changes
+ example_data = {
+ "id": 21,
+ "iid": 1,
+ "project_id": 4,
+ "title": "Blanditiis beatae suscipit hic assumenda et molestias nisi asperiores repellat et.",
+ "state": "reopened",
+ "created_at": "2015-02-02T19:49:39.159Z",
+ "updated_at": "2015-02-02T20:08:49.959Z",
+ "target_branch": "secret_token",
+ "source_branch": "version-1-9",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "name": "Chad Hamill",
+ "username": "jarrett",
+ "id": 5,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/b95567800f828948baf5f4160ebb2473?s=40&d=identicon",
+ "web_url": "https://gitlab.example.com/jarrett",
+ },
+ "assignee": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40&d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "reviewers": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "source_project_id": 4,
+ "target_project_id": 4,
+ "labels": [],
+ "description": "Qui voluptatibus placeat ipsa alias quasi. Deleniti rem ut sint. Option velit qui distinctio.",
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 4,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": None,
+ },
+ "merge_when_pipeline_succeeds": True,
+ "merge_status": "can_be_merged",
+ "detailed_merge_status": "can_be_merged",
+ "subscribed": True,
+ "sha": "8888888888888888888888888888888888888888",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 1,
+ "changes_count": "1",
+ "should_remove_source_branch": True,
+ "force_remove_source_branch": False,
+ "squash": False,
+ "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
+ "references": {
+ "short": "!1",
+ "relative": "!1",
+ "full": "my-group/my-project!1",
+ },
+ "discussion_locked": False,
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ "changes": [
+ {
+ "old_path": "VERSION",
+ "new_path": "VERSION",
+ "a_mode": "100644",
+ "b_mode": "100644",
+ "diff": "@@ -1 +1 @@\ -1.9.7\ +1.9.8",
+ "new_file": False,
+ "renamed_file": False,
+ "deleted_file": False,
+ }
+ ],
+ "overflow": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_8():
+ # Diff
+ example_data = [
+ {
+ "old_path": "README",
+ "new_path": "README",
+ "a_mode": "100644",
+ "b_mode": "100644",
+ "diff": "@@ -1 +1 @@\ -Title\ +README",
+ "new_file": False,
+ "renamed_file": False,
+ "deleted_file": False,
+ "generated_file": False,
+ },
+ {
+ "old_path": "VERSION",
+ "new_path": "VERSION",
+ "a_mode": "100644",
+ "b_mode": "100644",
+ "diff": "@@\ -1.9.7\ +1.9.8",
+ "new_file": False,
+ "renamed_file": False,
+ "deleted_file": False,
+ "generated_file": False,
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Diffs"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_9():
+ # Pipelines
+ example_data = [
+ {
+ "id": 77,
+ "sha": "959e04d7c7a30600c894bd3c0cd0e1ce7f42c11d",
+ "ref": "main",
+ "status": "success",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipelines"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_10():
+ # Merge Request
+ example_data = {
+ "id": 1,
+ "iid": 1,
+ "project_id": 3,
+ "title": "test1",
+ "description": "fixed login page css paddings",
+ "state": "merged",
+ "imported": False,
+ "imported_from": "none",
+ "created_at": "2017-04-29T08:46:00Z",
+ "updated_at": "2017-04-29T08:46:00Z",
+ "target_branch": "main",
+ "source_branch": "test1",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignee": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "source_project_id": 2,
+ "target_project_id": 3,
+ "labels": ["Community contribution", "Manage"],
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": "2018-09-22",
+ "start_date": "2018-08-08",
+ "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1",
+ },
+ "merge_when_pipeline_succeeds": True,
+ "merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
+ "merge_error": None,
+ "sha": "8888888888888888888888888888888888888888",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 1,
+ "discussion_locked": None,
+ "should_remove_source_branch": True,
+ "force_remove_source_branch": False,
+ "allow_collaboration": False,
+ "allow_maintainer_to_push": False,
+ "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
+ "references": {
+ "short": "!1",
+ "relative": "!1",
+ "full": "my-group/my-project!1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "squash": False,
+ "subscribed": False,
+ "changes_count": "1",
+ "merged_by": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merge_user": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merged_at": "2018-09-07T11:16:17.520Z",
+ "prepared_at": "2018-09-04T11:16:17.520Z",
+ "closed_by": None,
+ "closed_at": None,
+ "latest_build_started_at": "2018-09-07T07:27:38.472Z",
+ "latest_build_finished_at": "2018-09-07T08:07:06.012Z",
+ "first_deployed_to_production_at": None,
+ "pipeline": {
+ "id": 29626725,
+ "sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f",
+ "ref": "patch-28",
+ "status": "success",
+ "web_url": "https://gitlab.example.com/my-group/my-project/pipelines/29626725",
+ },
+ "diff_refs": {
+ "base_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00",
+ "head_sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f",
+ "start_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00",
+ },
+ "diverged_commits_count": 2,
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_11():
+ example_data = {
+ "id": 1,
+ "iid": 1,
+ "project_id": 3,
+ "title": "test1",
+ "description": "fixed login page css paddings",
+ "state": "merged",
+ "created_at": "2017-04-29T08:46:00Z",
+ "updated_at": "2017-04-29T08:46:00Z",
+ "target_branch": "main",
+ "source_branch": "test1",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignee": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "reviewers": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "source_project_id": 2,
+ "target_project_id": 3,
+ "labels": ["Community contribution", "Manage"],
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": "2018-09-22",
+ "start_date": "2018-08-08",
+ "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1",
+ },
+ "merge_when_pipeline_succeeds": True,
+ "merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
+ "merge_error": None,
+ "sha": "8888888888888888888888888888888888888888",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 1,
+ "discussion_locked": None,
+ "should_remove_source_branch": True,
+ "force_remove_source_branch": False,
+ "allow_collaboration": False,
+ "allow_maintainer_to_push": False,
+ "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
+ "references": {
+ "short": "!1",
+ "relative": "!1",
+ "full": "my-group/my-project!1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "squash": False,
+ "subscribed": False,
+ "changes_count": "1",
+ "merged_by": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merge_user": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merged_at": "2018-09-07T11:16:17.520Z",
+ "prepared_at": "2018-09-04T11:16:17.520Z",
+ "closed_by": None,
+ "closed_at": None,
+ "latest_build_started_at": "2018-09-07T07:27:38.472Z",
+ "latest_build_finished_at": "2018-09-07T08:07:06.012Z",
+ "first_deployed_to_production_at": None,
+ "pipeline": {
+ "id": 29626725,
+ "sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f",
+ "ref": "patch-28",
+ "status": "success",
+ "web_url": "https://gitlab.example.com/my-group/my-project/pipelines/29626725",
+ },
+ "diff_refs": {
+ "base_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00",
+ "head_sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f",
+ "start_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00",
+ },
+ "diverged_commits_count": 2,
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_12():
+ example_data = {
+ "id": 1,
+ "iid": 1,
+ "project_id": 3,
+ "title": "test1",
+ "description": "fixed login page css paddings",
+ "state": "merged",
+ "created_at": "2017-04-29T08:46:00Z",
+ "updated_at": "2017-04-29T08:46:00Z",
+ "target_branch": "main",
+ "source_branch": "test1",
+ "upvotes": 0,
+ "downvotes": 0,
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignee": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "admin",
+ "state": "active",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/admin",
+ },
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "reviewers": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "source_project_id": 2,
+ "target_project_id": 3,
+ "labels": ["Community contribution", "Manage"],
+ "draft": False,
+ "work_in_progress": False,
+ "milestone": {
+ "id": 5,
+ "iid": 1,
+ "project_id": 3,
+ "title": "v2.0",
+ "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
+ "state": "closed",
+ "created_at": "2015-02-02T19:49:26.013Z",
+ "updated_at": "2015-02-02T19:49:26.013Z",
+ "due_date": "2018-09-22",
+ "start_date": "2018-08-08",
+ "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1",
+ },
+ "merge_when_pipeline_succeeds": False,
+ "merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
+ "merge_error": None,
+ "sha": "8888888888888888888888888888888888888888",
+ "merge_commit_sha": None,
+ "squash_commit_sha": None,
+ "user_notes_count": 1,
+ "discussion_locked": None,
+ "should_remove_source_branch": True,
+ "force_remove_source_branch": False,
+ "allow_collaboration": False,
+ "allow_maintainer_to_push": False,
+ "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
+ "references": {
+ "short": "!1",
+ "relative": "!1",
+ "full": "my-group/my-project!1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "squash": False,
+ "subscribed": False,
+ "changes_count": "1",
+ "merged_by": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merge_user": {
+ "id": 87854,
+ "name": "Douwe Maan",
+ "username": "DouweM",
+ "state": "active",
+ "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
+ "web_url": "https://gitlab.com/DouweM",
+ },
+ "merged_at": "2018-09-07T11:16:17.520Z",
+ "prepared_at": "2018-09-04T11:16:17.520Z",
+ "closed_by": None,
+ "closed_at": None,
+ "latest_build_started_at": "2018-09-07T07:27:38.472Z",
+ "latest_build_finished_at": "2018-09-07T08:07:06.012Z",
+ "first_deployed_to_production_at": None,
+ "pipeline": {
+ "id": 29626725,
+ "sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f",
+ "ref": "patch-28",
+ "status": "success",
+ "web_url": "https://gitlab.example.com/my-group/my-project/pipelines/29626725",
+ },
+ "diff_refs": {
+ "base_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00",
+ "head_sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f",
+ "start_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00",
+ },
+ "diverged_commits_count": 2,
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_13():
+ example_data = {"rebase_in_progress": True}
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_14():
+ example_data = {"rebase_in_progress": True, "merge_error": None}
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_15():
+ example_data = {"rebase_in_progress": False, "merge_error": None}
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_16():
+ example_data = {
+ "rebase_in_progress": False,
+ "merge_error": "Rebase failed. Please rebase locally",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_17():
+ # Issues
+ example_data = [
+ {
+ "state": "opened",
+ "description": "Ratione dolores corrupti mollitia soluta quia.",
+ "author": {
+ "state": "active",
+ "id": 18,
+ "web_url": "https://gitlab.example.com/eileen.lowe",
+ "name": "Alexandra Bashirian",
+ "avatar_url": None,
+ "username": "eileen.lowe",
+ },
+ "milestone": {
+ "project_id": 1,
+ "description": "Ducimus nam enim ex consequatur cumque ratione.",
+ "state": "closed",
+ "due_date": None,
+ "iid": 2,
+ "created_at": "2016-01-04T15:31:39.996Z",
+ "title": "v4.0",
+ "id": 17,
+ "updated_at": "2016-01-04T15:31:39.996Z",
+ },
+ "project_id": 1,
+ "assignee": {
+ "state": "active",
+ "id": 1,
+ "name": "Administrator",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ },
+ "updated_at": "2016-01-04T15:31:51.081Z",
+ "id": 76,
+ "title": "Consequatur vero maxime deserunt laboriosam est voluptas dolorem.",
+ "created_at": "2016-01-04T15:31:51.081Z",
+ "iid": 6,
+ "labels": [],
+ "user_notes_count": 1,
+ "changes_count": "1",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issues"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_18():
+ # Comments on Merge Request
+ example_data = [
+ {
+ "state": "opened",
+ "description": "Ratione dolores corrupti mollitia soluta quia.",
+ "author": {
+ "state": "active",
+ "id": 18,
+ "web_url": "https://gitlab.example.com/eileen.lowe",
+ "name": "Alexandra Bashirian",
+ "avatar_url": None,
+ "username": "eileen.lowe",
+ },
+ "milestone": {
+ "project_id": 1,
+ "description": "Ducimus nam enim ex consequatur cumque ratione.",
+ "state": "closed",
+ "due_date": None,
+ "iid": 2,
+ "created_at": "2016-01-04T15:31:39.996Z",
+ "title": "v4.0",
+ "id": 17,
+ "updated_at": "2016-01-04T15:31:39.996Z",
+ },
+ "project_id": 1,
+ "assignee": {
+ "state": "active",
+ "id": 1,
+ "name": "Administrator",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ },
+ "updated_at": "2016-01-04T15:31:51.081Z",
+ "id": 76,
+ "title": "Consequatur vero maxime deserunt laboriosam est voluptas dolorem.",
+ "created_at": "2016-01-04T15:31:51.081Z",
+ "iid": 6,
+ "labels": [],
+ "user_notes_count": 1,
+ "changes_count": "1",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issues"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_19():
+ # Time tracking for Merge Request
+ example_data = {
+ "human_time_estimate": "2h",
+ "human_total_time_spent": "1h",
+ "time_estimate": 7200,
+ "total_time_spent": 3600,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "TimeStats"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_20():
+ example_data = {
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "TimeStats"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_merge_request_response_21():
+ # Merge diff versions
+ example_data = [
+ {
+ "id": 110,
+ "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
+ "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+ "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+ "created_at": "2016-07-26T14:44:48.926Z",
+ "merge_request_id": 105,
+ "state": "collected",
+ "real_size": "1",
+ "patch_id_sha": "d504412d5b6e6739647e752aff8e468dde093f2f",
+ },
+ {
+ "id": 108,
+ "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24",
+ "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+ "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+ "created_at": "2016-07-25T14:21:33.028Z",
+ "merge_request_id": 105,
+ "state": "collected",
+ "real_size": "1",
+ "patch_id_sha": "72c30d1f0115fc1d2bb0b29b24dc2982cbcdfd32",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Diffs"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_1():
+ example_data = [
+ {
+ "state": "opened",
+ "description": "Ratione dolores corrupti mollitia soluta quia.",
+ "author": {
+ "state": "active",
+ "id": 18,
+ "web_url": "https://gitlab.example.com/eileen.lowe",
+ "name": "Alexandra Bashirian",
+ "avatar_url": None,
+ "username": "eileen.lowe",
+ },
+ "milestone": {
+ "project_id": 1,
+ "description": "Ducimus nam enim ex consequatur cumque ratione.",
+ "state": "closed",
+ "due_date": None,
+ "iid": 2,
+ "created_at": "2016-01-04T15:31:39.996Z",
+ "title": "v4.0",
+ "id": 17,
+ "updated_at": "2016-01-04T15:31:39.996Z",
+ },
+ "project_id": 1,
+ "assignees": [
+ {
+ "state": "active",
+ "id": 1,
+ "name": "Administrator",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ }
+ ],
+ "assignee": {
+ "state": "active",
+ "id": 1,
+ "name": "Administrator",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ },
+ "type": "ISSUE",
+ "updated_at": "2016-01-04T15:31:51.081Z",
+ "closed_at": None,
+ "closed_by": None,
+ "id": 76,
+ "title": "Consequatur vero maxime deserunt laboriosam est voluptas dolorem.",
+ "created_at": "2016-01-04T15:31:51.081Z",
+ "moved_to_id": None,
+ "iid": 6,
+ "labels": ["foo", "bar"],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "user_notes_count": 1,
+ "due_date": "2016-07-22",
+ "imported": False,
+ "imported_from": "none",
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/6",
+ "references": {
+ "short": "#6",
+ "relative": "my-group/my-project#6",
+ "full": "my-group/my-project#6",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "has_tasks": True,
+ "task_status": "10 of 15 tasks completed",
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "_links": {
+ "self": "http://gitlab.example.com/api/v4/projects/1/issues/76",
+ "notes": "http://gitlab.example.com/api/v4/projects/1/issues/76/notes",
+ "award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/76/award_emoji",
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issues"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_2():
+ example_data = [
+ {
+ "state": "opened",
+ "description": "Ratione dolores corrupti mollitia soluta quia.",
+ "weight": None,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issues"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_3():
+ example_data = {
+ "project_id": 4,
+ "description": "Omnis vero earum sunt corporis dolor et placeat.",
+ "epic_iid": 5,
+ "epic": {
+ "id": 42,
+ "iid": 5,
+ "title": "My epic epic",
+ "url": "/groups/h5bp/-/epics/5",
+ "group_id": 8,
+ },
+ "iteration": {
+ "id": 90,
+ "iid": 4,
+ "sequence": 2,
+ "group_id": 162,
+ "title": None,
+ "description": None,
+ "state": 2,
+ "created_at": "2022-03-14T05:21:11.929Z",
+ "updated_at": "2022-03-14T05:21:11.929Z",
+ "start_date": "2022-03-08",
+ "due_date": "2022-03-14",
+ "web_url": "https://gitlab.com/groups/my-group/-/iterations/90",
+ },
+ "state": "opened",
+ "health_status": "on_track",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issue"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_4():
+ example_data = [
+ {
+ "project_id": 4,
+ "milestone": {
+ "due_date": None,
+ "project_id": 4,
+ "state": "closed",
+ "description": "Rerum est voluptatem provident consequuntur molestias similique ipsum dolor.",
+ "iid": 3,
+ "id": 11,
+ "title": "v3.0",
+ "created_at": "2016-01-04T15:31:39.788Z",
+ "updated_at": "2016-01-04T15:31:39.788Z",
+ },
+ "author": {
+ "state": "active",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ "id": 1,
+ "name": "Administrator",
+ },
+ "description": "Omnis vero earum sunt corporis dolor et placeat.",
+ "state": "closed",
+ "iid": 1,
+ "assignees": [
+ {
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/lennie",
+ "state": "active",
+ "username": "lennie",
+ "id": 9,
+ "name": "Dr. Luella Kovacek",
+ }
+ ],
+ "assignee": {
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/lennie",
+ "state": "active",
+ "username": "lennie",
+ "id": 9,
+ "name": "Dr. Luella Kovacek",
+ },
+ "type": "ISSUE",
+ "labels": ["foo", "bar"],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "id": 41,
+ "title": "Ut commodi ullam eos dolores perferendis nihil sunt.",
+ "updated_at": "2016-01-04T15:31:46.176Z",
+ "created_at": "2016-01-04T15:31:46.176Z",
+ "closed_at": None,
+ "closed_by": None,
+ "user_notes_count": 1,
+ "due_date": None,
+ "imported": False,
+ "imported_from": "none",
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/1",
+ "references": {
+ "short": "#1",
+ "relative": "my-project#1",
+ "full": "my-group/my-project#1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "has_tasks": True,
+ "task_status": "10 of 15 tasks completed",
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "_links": {
+ "self": "http://gitlab.example.com/api/v4/projects/4/issues/41",
+ "notes": "http://gitlab.example.com/api/v4/projects/4/issues/41/notes",
+ "award_emoji": "http://gitlab.example.com/api/v4/projects/4/issues/41/award_emoji",
+ "project": "http://gitlab.example.com/api/v4/projects/4",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ "weight": None,
+ "epic_iid": 5,
+ "epic": {
+ "id": 42,
+ "iid": 5,
+ "title": "My epic epic",
+ "url": "/groups/h5bp/-/epics/5",
+ "group_id": 8,
+ },
+ "health_status": "at_risk",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issues"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_5():
+ example_data = [
+ {
+ "project_id": 4,
+ "milestone": {
+ "due_date": None,
+ "project_id": 4,
+ "state": "closed",
+ "description": "Rerum est voluptatem provident consequuntur molestias similique ipsum dolor.",
+ "iid": 3,
+ "id": 11,
+ "title": "v3.0",
+ "created_at": "2016-01-04T15:31:39.788Z",
+ "updated_at": "2016-01-04T15:31:39.788Z",
+ },
+ "author": {
+ "state": "active",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ "id": 1,
+ "name": "Administrator",
+ },
+ "description": "Omnis vero earum sunt corporis dolor et placeat.",
+ "state": "closed",
+ "iid": 1,
+ "assignees": [
+ {
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/lennie",
+ "state": "active",
+ "username": "lennie",
+ "id": 9,
+ "name": "Dr. Luella Kovacek",
+ }
+ ],
+ "assignee": {
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/lennie",
+ "state": "active",
+ "username": "lennie",
+ "id": 9,
+ "name": "Dr. Luella Kovacek",
+ },
+ "type": "ISSUE",
+ "labels": ["foo", "bar"],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "id": 41,
+ "title": "Ut commodi ullam eos dolores perferendis nihil sunt.",
+ "updated_at": "2016-01-04T15:31:46.176Z",
+ "created_at": "2016-01-04T15:31:46.176Z",
+ "closed_at": "2016-01-05T15:31:46.176Z",
+ "closed_by": {
+ "state": "active",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ "id": 1,
+ "name": "Administrator",
+ },
+ "user_notes_count": 1,
+ "due_date": "2016-07-22",
+ "imported": False,
+ "imported_from": "none",
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/1",
+ "references": {
+ "short": "#1",
+ "relative": "#1",
+ "full": "my-group/my-project#1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "has_tasks": True,
+ "task_status": "10 of 15 tasks completed",
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "_links": {
+ "self": "http://gitlab.example.com/api/v4/projects/4/issues/41",
+ "notes": "http://gitlab.example.com/api/v4/projects/4/issues/41/notes",
+ "award_emoji": "http://gitlab.example.com/api/v4/projects/4/issues/41/award_emoji",
+ "project": "http://gitlab.example.com/api/v4/projects/4",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ "weight": None,
+ "epic_iid": 5,
+ "epic": {
+ "id": 42,
+ "iid": 5,
+ "title": "My epic epic",
+ "url": "/groups/h5bp/-/epics/5",
+ "group_id": 8,
+ },
+ "health_status": "at_risk",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issues"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_6():
+ example_data = {
+ "id": 1,
+ "milestone": {
+ "due_date": None,
+ "project_id": 4,
+ "state": "closed",
+ "description": "Rerum est voluptatem provident consequuntur molestias similique ipsum dolor.",
+ "iid": 3,
+ "id": 11,
+ "title": "v3.0",
+ "created_at": "2016-01-04T15:31:39.788Z",
+ "updated_at": "2016-01-04T15:31:39.788Z",
+ "closed_at": "2016-01-05T15:31:46.176Z",
+ },
+ "author": {
+ "state": "active",
+ "web_url": "https://gitlab.example.com/root",
+ "avatar_url": None,
+ "username": "root",
+ "id": 1,
+ "name": "Administrator",
+ },
+ "description": "Omnis vero earum sunt corporis dolor et placeat.",
+ "state": "closed",
+ "iid": 1,
+ "assignees": [
+ {
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/lennie",
+ "state": "active",
+ "username": "lennie",
+ "id": 9,
+ "name": "Dr. Luella Kovacek",
+ }
+ ],
+ "assignee": {
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/lennie",
+ "state": "active",
+ "username": "lennie",
+ "id": 9,
+ "name": "Dr. Luella Kovacek",
+ },
+ "type": "ISSUE",
+ "labels": [],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "title": "Ut commodi ullam eos dolores perferendis nihil sunt.",
+ "updated_at": "2016-01-04T15:31:46.176Z",
+ "created_at": "2016-01-04T15:31:46.176Z",
+ "closed_at": None,
+ "closed_by": None,
+ "subscribed": False,
+ "user_notes_count": 1,
+ "due_date": None,
+ "imported": False,
+ "imported_from": "none",
+ "web_url": "http://example.com/my-group/my-project/issues/1",
+ "references": {
+ "short": "#1",
+ "relative": "#1",
+ "full": "my-group/my-project#1",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ "weight": None,
+ "has_tasks": False,
+ "_links": {
+ "self": "http://gitlab.example:3000/api/v4/projects/1/issues/1",
+ "notes": "http://gitlab.example:3000/api/v4/projects/1/issues/1/notes",
+ "award_emoji": "http://gitlab.example:3000/api/v4/projects/1/issues/1/award_emoji",
+ "project": "http://gitlab.example:3000/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "moved_to_id": None,
+ "service_desk_reply_to": "service.desk@gitlab.com",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issue"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_7():
+ example_data = {
+ "project_id": 4,
+ "id": 84,
+ "created_at": "2016-01-07T12:44:33.959Z",
+ "iid": 14,
+ "title": "Issues with auth",
+ "state": "opened",
+ "assignees": [],
+ "assignee": None,
+ "type": "ISSUE",
+ "labels": ["bug"],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "author": {
+ "name": "Alexandra Bashirian",
+ "avatar_url": None,
+ "state": "active",
+ "web_url": "https://gitlab.example.com/eileen.lowe",
+ "id": 18,
+ "username": "eileen.lowe",
+ },
+ "description": None,
+ "updated_at": "2016-01-07T12:44:33.959Z",
+ "closed_at": None,
+ "closed_by": None,
+ "milestone": None,
+ "subscribed": True,
+ "user_notes_count": 0,
+ "due_date": None,
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/14",
+ "references": {
+ "short": "#14",
+ "relative": "#14",
+ "full": "my-group/my-project#14",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "_links": {
+ "self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
+ "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
+ "award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issue"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_8():
+ example_data = {
+ "id": 92,
+ "iid": 11,
+ "project_id": 5,
+ "title": "Sit voluptas tempora quisquam aut doloribus et.",
+ "description": "Repellat voluptas quibusdam voluptatem exercitationem.",
+ "state": "opened",
+ "created_at": "2016-04-05T21:41:45.652Z",
+ "updated_at": "2016-04-07T12:20:17.596Z",
+ "closed_at": None,
+ "closed_by": None,
+ "labels": [],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "milestone": None,
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "assignee": {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ },
+ "type": "ISSUE",
+ "author": {
+ "name": "Kris Steuber",
+ "username": "solon.cremin",
+ "id": 10,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/solon.cremin",
+ },
+ "due_date": None,
+ "imported": False,
+ "imported_from": "none",
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/11",
+ "references": {
+ "short": "#11",
+ "relative": "#11",
+ "full": "my-group/my-project#11",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "_links": {
+ "self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
+ "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
+ "award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issue"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_9():
+ example_data = {
+ "id": 290,
+ "iid": 1,
+ "project_id": 143,
+ "title": "foo",
+ "description": "closed",
+ "state": "opened",
+ "created_at": "2021-09-14T22:24:11.696Z",
+ "updated_at": "2021-09-14T22:24:11.696Z",
+ "closed_at": None,
+ "closed_by": None,
+ "labels": [],
+ "milestone": None,
+ "assignees": [
+ {
+ "id": 179,
+ "name": "John Doe2",
+ "username": "john",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/john",
+ }
+ ],
+ "author": {
+ "id": 179,
+ "name": "John Doe2",
+ "username": "john",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/john",
+ },
+ "type": "ISSUE",
+ "assignee": {
+ "id": 179,
+ "name": "John Doe2",
+ "username": "john",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/john",
+ },
+ "user_notes_count": 1,
+ "merge_requests_count": 0,
+ "upvotes": 0,
+ "downvotes": 0,
+ "due_date": None,
+ "imported": False,
+ "imported_from": "none",
+ "confidential": False,
+ "discussion_locked": None,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "web_url": "https://gitlab.example.com/namespace1/project2/-/issues/1",
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ "blocking_issues_count": 0,
+ "has_tasks": False,
+ "_links": {
+ "self": "https://gitlab.example.com/api/v4/projects/143/issues/1",
+ "notes": "https://gitlab.example.com/api/v4/projects/143/issues/1/notes",
+ "award_emoji": "https://gitlab.example.com/api/v4/projects/143/issues/1/award_emoji",
+ "project": "https://gitlab.example.com/api/v4/projects/143",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "references": {
+ "short": "#1",
+ "relative": "#1",
+ "full": "namespace1/project2#1",
+ },
+ "subscribed": True,
+ "moved_to_id": None,
+ "service_desk_reply_to": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issue"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_10():
+ example_data = {
+ "id": 92,
+ "iid": 11,
+ "project_id": 5,
+ "title": "Sit voluptas tempora quisquam aut doloribus et.",
+ "description": "Repellat voluptas quibusdam voluptatem exercitationem.",
+ "state": "opened",
+ "created_at": "2016-04-05T21:41:45.652Z",
+ "updated_at": "2016-04-07T12:20:17.596Z",
+ "closed_at": None,
+ "closed_by": None,
+ "labels": [],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "milestone": None,
+ "assignees": [
+ {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ }
+ ],
+ "assignee": {
+ "name": "Miss Monserrate Beier",
+ "username": "axel.block",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/axel.block",
+ },
+ "type": "ISSUE",
+ "author": {
+ "name": "Kris Steuber",
+ "username": "solon.cremin",
+ "id": 10,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/solon.cremin",
+ },
+ "due_date": None,
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/11",
+ "references": {
+ "short": "#11",
+ "relative": "#11",
+ "full": "my-group/my-project#11",
+ },
+ "time_stats": {
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ },
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "_links": {
+ "self": "http://gitlab.example.com/api/v4/projects/1/issues/2",
+ "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes",
+ "award_emoji": "http://gitlab.example.com/api/v4/projects/1/issues/2/award_emoji",
+ "project": "http://gitlab.example.com/api/v4/projects/1",
+ "closed_as_duplicate_of": "http://gitlab.example.com/api/v4/projects/1/issues/75",
+ },
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issue"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_11():
+ example_data = {
+ "id": 93,
+ "iid": 12,
+ "project_id": 5,
+ "title": "Incidunt et rerum ea expedita iure quibusdam.",
+ "description": "Et cumque architecto sed aut ipsam.",
+ "state": "opened",
+ "created_at": "2016-04-05T21:41:45.217Z",
+ "updated_at": "2016-04-07T13:02:37.905Z",
+ "labels": [],
+ "upvotes": 4,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "milestone": None,
+ "assignee": {
+ "name": "Edwardo Grady",
+ "username": "keyon",
+ "id": 21,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/3e6f06a86cf27fa8b56f3f74f7615987?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/keyon",
+ },
+ "type": "ISSUE",
+ "closed_at": None,
+ "closed_by": None,
+ "author": {
+ "name": "Vivian Hermann",
+ "username": "orville",
+ "id": 11,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/orville",
+ },
+ "subscribed": False,
+ "due_date": None,
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/12",
+ "references": {
+ "short": "#12",
+ "relative": "#12",
+ "full": "my-group/my-project#12",
+ },
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Issue"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_12():
+ example_data = {
+ "id": 112,
+ "project": {
+ "id": 5,
+ "name": "GitLab CI/CD",
+ "name_with_namespace": "GitLab Org / GitLab CI/CD",
+ "path": "gitlab-ci",
+ "path_with_namespace": "gitlab-org/gitlab-ci",
+ },
+ "author": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "action_name": "marked",
+ "target_type": "Issue",
+ "target": {
+ "id": 93,
+ "iid": 10,
+ "project_id": 5,
+ "title": "Vel voluptas atque dicta mollitia adipisci qui at.",
+ "description": "Tempora laboriosam sint magni sed voluptas similique.",
+ "state": "closed",
+ "created_at": "2016-06-17T07:47:39.486Z",
+ "updated_at": "2016-07-01T11:09:13.998Z",
+ "labels": [],
+ "milestone": {
+ "id": 26,
+ "iid": 1,
+ "project_id": 5,
+ "title": "v0.0",
+ "description": "Accusantium nostrum rerum quae quia quis nesciunt suscipit id.",
+ "state": "closed",
+ "created_at": "2016-06-17T07:47:33.832Z",
+ "updated_at": "2016-06-17T07:47:33.832Z",
+ "due_date": None,
+ },
+ "assignees": [
+ {
+ "name": "Jarret O'Keefe",
+ "username": "francisca",
+ "id": 14,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/a7fa515d53450023c83d62986d0658a8?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/francisca",
+ }
+ ],
+ "assignee": {
+ "name": "Jarret O'Keefe",
+ "username": "francisca",
+ "id": 14,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/a7fa515d53450023c83d62986d0658a8?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/francisca",
+ },
+ "type": "ISSUE",
+ "author": {
+ "name": "Maxie Medhurst",
+ "username": "craig_rutherford",
+ "id": 12,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/craig_rutherford",
+ },
+ "subscribed": True,
+ "user_notes_count": 7,
+ "upvotes": 0,
+ "downvotes": 0,
+ "merge_requests_count": 0,
+ "due_date": None,
+ "web_url": "http://gitlab.example.com/my-group/my-project/issues/10",
+ "references": {
+ "short": "#10",
+ "relative": "#10",
+ "full": "my-group/my-project#10",
+ },
+ "confidential": False,
+ "discussion_locked": False,
+ "issue_type": "issue",
+ "severity": "UNKNOWN",
+ "task_completion_status": {"count": 0, "completed_count": 0},
+ },
+ "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/issues/10",
+ "body": "Vel voluptas atque dicta mollitia adipisci qui at.",
+ "state": "pending",
+ "created_at": "2016-07-01T11:09:13.992Z",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ToDo"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_13():
+ example_data = {
+ "id": 699,
+ "type": None,
+ "body": "Lets promote this to an epic",
+ "attachment": None,
+ "author": {
+ "id": 1,
+ "name": "Alexandra Bashirian",
+ "username": "eileen.lowe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "https://gitlab.example.com/eileen.lowe",
+ },
+ "created_at": "2020-12-03T12:27:17.844Z",
+ "updated_at": "2020-12-03T12:27:17.844Z",
+ "system": False,
+ "noteable_id": 461,
+ "noteable_type": "Issue",
+ "resolvable": False,
+ "confidential": False,
+ "noteable_iid": 33,
+ "commands_changes": {"promote_to_epic": True},
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Comment"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_14():
+ example_data = {
+ "human_time_estimate": "3h 30m",
+ "human_total_time_spent": None,
+ "time_estimate": 12600,
+ "total_time_spent": 0,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "TimeStats"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_issues_response_15():
+ example_data = {
+ "human_time_estimate": None,
+ "human_total_time_spent": None,
+ "time_estimate": 0,
+ "total_time_spent": 0,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "TimeStats"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_1():
+ example_data = [
+ {
+ "id": 47,
+ "iid": 12,
+ "project_id": 1,
+ "status": "pending",
+ "source": "push",
+ "ref": "new-pipeline",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "name": "Build pipeline",
+ "web_url": "https://example.com/foo/bar/pipelines/47",
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ },
+ {
+ "id": 48,
+ "iid": 13,
+ "project_id": 1,
+ "status": "pending",
+ "source": "web",
+ "ref": "new-pipeline",
+ "sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a",
+ "name": "Build pipeline",
+ "web_url": "https://example.com/foo/bar/pipelines/48",
+ "created_at": "2016-08-12T10:06:04.561Z",
+ "updated_at": "2016-08-12T10:09:56.223Z",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipelines"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_2():
+ example_data = {
+ "id": 46,
+ "iid": 11,
+ "project_id": 1,
+ "name": "Build pipeline",
+ "status": "success",
+ "ref": "main",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "tag": False,
+ "yaml_errors": None,
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root",
+ },
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "started_at": None,
+ "finished_at": "2016-08-11T11:32:35.145Z",
+ "committed_at": None,
+ "duration": 123.65,
+ "queued_duration": 0.010,
+ "coverage": "30.0",
+ "web_url": "https://example.com/foo/bar/pipelines/46",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipeline"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_3():
+ example_data = [
+ {"key": "RUN_NIGHTLY_BUILD", "variable_type": "env_var", "value": "true"},
+ {"key": "foo", "value": "bar"},
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "PipelineVariables"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_4():
+ example_data = {
+ "total_time": 5,
+ "total_count": 1,
+ "success_count": 1,
+ "failed_count": 0,
+ "skipped_count": 0,
+ "error_count": 0,
+ "test_suites": [
+ {
+ "name": "Secure",
+ "total_time": 5,
+ "total_count": 1,
+ "success_count": 1,
+ "failed_count": 0,
+ "skipped_count": 0,
+ "error_count": 0,
+ "test_cases": [
+ {
+ "status": "success",
+ "name": "Security Reports can create an auto-remediation MR",
+ "classname": "vulnerability_management_spec",
+ "execution_time": 5,
+ "system_output": None,
+ "stack_trace": None,
+ }
+ ],
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "TestReport"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_5():
+ example_data = {
+ "total": {
+ "time": 1904,
+ "count": 3363,
+ "success": 3351,
+ "failed": 0,
+ "skipped": 12,
+ "error": 0,
+ "suite_error": None,
+ },
+ "test_suites": [
+ {
+ "name": "test",
+ "total_time": 1904,
+ "total_count": 3363,
+ "success_count": 3351,
+ "failed_count": 0,
+ "skipped_count": 12,
+ "error_count": 0,
+ "build_ids": [66004],
+ "suite_error": None,
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "TestReport"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_6():
+ example_data = {
+ "total": {
+ "time": 1904,
+ "count": 3363,
+ "success": 3351,
+ "failed": 0,
+ "skipped": 12,
+ "error": 0,
+ "suite_error": None,
+ },
+ "test_suites": [
+ {
+ "name": "test",
+ "total_time": 1904,
+ "total_count": 3363,
+ "success_count": 3351,
+ "failed_count": 0,
+ "skipped_count": 12,
+ "error_count": 0,
+ "build_ids": [66004],
+ "suite_error": None,
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "TestReport"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_7():
+ example_data = {
+ "id": 287,
+ "iid": 144,
+ "project_id": 21,
+ "name": "Build pipeline",
+ "sha": "50f0acb76a40e34a4ff304f7347dcc6587da8a14",
+ "ref": "main",
+ "status": "success",
+ "source": "push",
+ "created_at": "2022-09-21T01:05:07.200Z",
+ "updated_at": "2022-09-21T01:05:50.185Z",
+ "web_url": "http://127.0.0.1:3000/test-group/test-project/-/pipelines/287",
+ "before_sha": "8a24fb3c5877a6d0b611ca41fc86edc174593e2b",
+ "tag": False,
+ "yaml_errors": None,
+ "user": {
+ "id": 1,
+ "username": "root",
+ "name": "Administrator",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://127.0.0.1:3000/root",
+ },
+ "started_at": "2022-09-21T01:05:14.197Z",
+ "finished_at": "2022-09-21T01:05:50.175Z",
+ "committed_at": None,
+ "duration": 34,
+ "queued_duration": 6,
+ "coverage": None,
+ "detailed_status": {
+ "icon": "status_success",
+ "text": "passed",
+ "label": "passed",
+ "group": "success",
+ "tooltip": "passed",
+ "has_details": False,
+ "details_path": "/test-group/test-project/-/pipelines/287",
+ "illustration": None,
+ "favicon": "/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipeline"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_8():
+ example_data = {
+ "id": 61,
+ "iid": 21,
+ "project_id": 1,
+ "sha": "384c444e840a515b23f21915ee5766b87068a70d",
+ "ref": "main",
+ "status": "pending",
+ "before_sha": "0000000000000000000000000000000000000000",
+ "tag": False,
+ "yaml_errors": None,
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root",
+ },
+ "created_at": "2016-11-04T09:36:13.747Z",
+ "updated_at": "2016-11-04T09:36:13.977Z",
+ "started_at": None,
+ "finished_at": None,
+ "committed_at": None,
+ "duration": None,
+ "queued_duration": 0.010,
+ "coverage": None,
+ "web_url": "https://example.com/foo/bar/pipelines/61",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipeline"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_9():
+ example_data = {
+ "id": 46,
+ "iid": 11,
+ "project_id": 1,
+ "status": "pending",
+ "ref": "main",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "tag": False,
+ "yaml_errors": None,
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root",
+ },
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "started_at": None,
+ "finished_at": "2016-08-11T11:32:35.145Z",
+ "committed_at": None,
+ "duration": None,
+ "queued_duration": 0.010,
+ "coverage": None,
+ "web_url": "https://example.com/foo/bar/pipelines/46",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipeline"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_10():
+ example_data = {
+ "id": 46,
+ "iid": 11,
+ "project_id": 1,
+ "status": "canceled",
+ "ref": "main",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "tag": False,
+ "yaml_errors": None,
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root",
+ },
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "started_at": None,
+ "finished_at": "2016-08-11T11:32:35.145Z",
+ "committed_at": None,
+ "duration": None,
+ "queued_duration": 0.010,
+ "coverage": None,
+ "web_url": "https://example.com/foo/bar/pipelines/46",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipeline"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_pipeline_response_11():
+ example_data = {
+ "id": 46,
+ "iid": 11,
+ "project_id": 1,
+ "status": "running",
+ "ref": "main",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "tag": False,
+ "yaml_errors": None,
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root",
+ },
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "started_at": None,
+ "finished_at": "2016-08-11T11:32:35.145Z",
+ "committed_at": None,
+ "duration": None,
+ "queued_duration": 0.010,
+ "coverage": None,
+ "web_url": "https://example.com/foo/bar/pipelines/46",
+ "name": "Some new pipeline name",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipeline"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_1():
+ example_data = [
+ {
+ "id": 1,
+ "name": "Foobar Group",
+ "path": "foo-bar",
+ "description": "An interesting group",
+ "visibility": "public",
+ "share_with_group_lock": False,
+ "require_two_factor_authentication": False,
+ "two_factor_grace_period": 48,
+ "project_creation_level": "developer",
+ "auto_devops_enabled": None,
+ "subgroup_creation_level": "owner",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "mentions_disabled": None,
+ "lfs_enabled": True,
+ "default_branch": None,
+ "default_branch_protection": 2,
+ "default_branch_protection_defaults": {
+ "allowed_to_push": [{"access_level": 40}],
+ "allow_force_push": False,
+ "allowed_to_merge": [{"access_level": 40}],
+ },
+ "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
+ "web_url": "http://localhost:3000/groups/foo-bar",
+ "request_access_enabled": False,
+ "repository_storage": "default",
+ "full_name": "Foobar Group",
+ "full_path": "foo-bar",
+ "file_template_project_id": 1,
+ "parent_id": None,
+ "created_at": "2020-01-15T12:36:29.590Z",
+ "ip_restriction_ranges": None,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Groups"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_2():
+ example_data = [
+ {
+ "id": 1,
+ "name": "Foobar Group",
+ "path": "foo-bar",
+ "description": "An interesting group",
+ "visibility": "public",
+ "share_with_group_lock": False,
+ "require_two_factor_authentication": False,
+ "two_factor_grace_period": 48,
+ "project_creation_level": "developer",
+ "auto_devops_enabled": None,
+ "subgroup_creation_level": "owner",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "mentions_disabled": None,
+ "lfs_enabled": True,
+ "default_branch": None,
+ "default_branch_protection": 2,
+ "default_branch_protection_defaults": {
+ "allowed_to_push": [{"access_level": 40}],
+ "allow_force_push": False,
+ "allowed_to_merge": [{"access_level": 40}],
+ },
+ "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
+ "web_url": "http://localhost:3000/groups/foo-bar",
+ "request_access_enabled": False,
+ "repository_storage": "default",
+ "full_name": "Foobar Group",
+ "full_path": "foo-bar",
+ "file_template_project_id": 1,
+ "parent_id": None,
+ "created_at": "2020-01-15T12:36:29.590Z",
+ "statistics": {
+ "storage_size": 363,
+ "repository_size": 33,
+ "wiki_size": 100,
+ "lfs_objects_size": 123,
+ "job_artifacts_size": 57,
+ "pipeline_artifacts_size": 0,
+ "packages_size": 0,
+ "snippets_size": 50,
+ "uploads_size": 0,
+ },
+ "wiki_access_level": "private",
+ "duo_features_enabled": True,
+ "lock_duo_features_enabled": False,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Groups"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_3():
+ example_data = [
+ {
+ "id": 1,
+ "name": "Foobar Group",
+ "path": "foo-bar",
+ "description": "An interesting group",
+ "visibility": "public",
+ "share_with_group_lock": False,
+ "require_two_factor_authentication": False,
+ "two_factor_grace_period": 48,
+ "project_creation_level": "developer",
+ "auto_devops_enabled": None,
+ "subgroup_creation_level": "owner",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "mentions_disabled": None,
+ "lfs_enabled": True,
+ "default_branch": None,
+ "default_branch_protection": 2,
+ "default_branch_protection_defaults": {
+ "allowed_to_push": [{"access_level": 40}],
+ "allow_force_push": False,
+ "allowed_to_merge": [{"access_level": 40}],
+ },
+ "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg",
+ "web_url": "http://gitlab.example.com/groups/foo-bar",
+ "request_access_enabled": False,
+ "repository_storage": "default",
+ "full_name": "Foobar Group",
+ "full_path": "foo-bar",
+ "file_template_project_id": 1,
+ "parent_id": 123,
+ "created_at": "2020-01-15T12:36:29.590Z",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Groups"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_4():
+ example_data = [
+ {
+ "id": 2,
+ "name": "Bar Group",
+ "path": "bar",
+ "description": "A subgroup of Foo Group",
+ "visibility": "public",
+ "share_with_group_lock": False,
+ "require_two_factor_authentication": False,
+ "two_factor_grace_period": 48,
+ "project_creation_level": "developer",
+ "auto_devops_enabled": None,
+ "subgroup_creation_level": "owner",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "mentions_disabled": None,
+ "lfs_enabled": True,
+ "default_branch": None,
+ "default_branch_protection": 2,
+ "default_branch_protection_defaults": {
+ "allowed_to_push": [{"access_level": 40}],
+ "allow_force_push": False,
+ "allowed_to_merge": [{"access_level": 40}],
+ },
+ "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/bar.jpg",
+ "web_url": "http://gitlab.example.com/groups/foo/bar",
+ "request_access_enabled": False,
+ "full_name": "Bar Group",
+ "full_path": "foo/bar",
+ "file_template_project_id": 1,
+ "parent_id": 123,
+ "created_at": "2020-01-15T12:36:29.590Z",
+ },
+ {
+ "id": 3,
+ "name": "Baz Group",
+ "path": "baz",
+ "description": "A subgroup of Bar Group",
+ "visibility": "public",
+ "share_with_group_lock": False,
+ "require_two_factor_authentication": False,
+ "two_factor_grace_period": 48,
+ "project_creation_level": "developer",
+ "auto_devops_enabled": None,
+ "subgroup_creation_level": "owner",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "mentions_disabled": None,
+ "lfs_enabled": True,
+ "default_branch": None,
+ "default_branch_protection": 2,
+ "default_branch_protection_defaults": {
+ "allowed_to_push": [{"access_level": 40}],
+ "allow_force_push": False,
+ "allowed_to_merge": [{"access_level": 40}],
+ },
+ "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/baz.jpg",
+ "web_url": "http://gitlab.example.com/groups/foo/bar/baz",
+ "request_access_enabled": False,
+ "full_name": "Baz Group",
+ "full_path": "foo/bar/baz",
+ "file_template_project_id": 1,
+ "parent_id": 123,
+ "created_at": "2020-01-15T12:36:29.590Z",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Groups"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_5():
+ # List groups
+ example_data = [
+ {
+ "id": 9,
+ "description": "foo",
+ "default_branch": "main",
+ "tag_list": [],
+ "topics": [],
+ "archived": False,
+ "visibility": "internal",
+ "ssh_url_to_repo": "git@gitlab.example.com/html5-boilerplate.git",
+ "http_url_to_repo": "http://gitlab.example.com/h5bp/html5-boilerplate.git",
+ "web_url": "http://gitlab.example.com/h5bp/html5-boilerplate",
+ "name": "Html5 Boilerplate",
+ "name_with_namespace": "Experimental / Html5 Boilerplate",
+ "path": "html5-boilerplate",
+ "path_with_namespace": "h5bp/html5-boilerplate",
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": True,
+ "created_at": "2016-04-05T21:40:50.169Z",
+ "last_activity_at": "2016-04-06T16:52:08.432Z",
+ "shared_runners_enabled": True,
+ "creator_id": 1,
+ "namespace": {
+ "id": 5,
+ "name": "Experimental",
+ "path": "h5bp",
+ "kind": "group",
+ },
+ "avatar_url": None,
+ "star_count": 1,
+ "forks_count": 0,
+ "open_issues_count": 3,
+ "public_jobs": True,
+ "shared_with_groups": [],
+ "request_access_enabled": False,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Projects"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_6():
+ # Groups shared projects
+ example_data = [
+ {
+ "id": 8,
+ "description": "Shared project for Html5 Boilerplate",
+ "name": "Html5 Boilerplate",
+ "name_with_namespace": "H5bp / Html5 Boilerplate",
+ "path": "html5-boilerplate",
+ "path_with_namespace": "h5bp/html5-boilerplate",
+ "created_at": "2020-04-27T06:13:22.642Z",
+ "default_branch": "main",
+ "tag_list": [],
+ "topics": [],
+ "ssh_url_to_repo": "ssh://git@gitlab.com/h5bp/html5-boilerplate.git",
+ "http_url_to_repo": "https://gitlab.com/h5bp/html5-boilerplate.git",
+ "web_url": "https://gitlab.com/h5bp/html5-boilerplate",
+ "readme_url": "https://gitlab.com/h5bp/html5-boilerplate/-/blob/main/README.md",
+ "avatar_url": None,
+ "star_count": 0,
+ "forks_count": 4,
+ "last_activity_at": "2020-04-27T06:13:22.642Z",
+ "namespace": {
+ "id": 28,
+ "name": "H5bp",
+ "path": "h5bp",
+ "kind": "group",
+ "full_path": "h5bp",
+ "parent_id": None,
+ "avatar_url": None,
+ "web_url": "https://gitlab.com/groups/h5bp",
+ },
+ "_links": {
+ "self": "https://gitlab.com/api/v4/projects/8",
+ "issues": "https://gitlab.com/api/v4/projects/8/issues",
+ "merge_requests": "https://gitlab.com/api/v4/projects/8/merge_requests",
+ "repo_branches": "https://gitlab.com/api/v4/projects/8/repository/branches",
+ "labels": "https://gitlab.com/api/v4/projects/8/labels",
+ "events": "https://gitlab.com/api/v4/projects/8/events",
+ "members": "https://gitlab.com/api/v4/projects/8/members",
+ },
+ "empty_repo": False,
+ "archived": False,
+ "visibility": "public",
+ "resolve_outdated_diff_discussions": False,
+ "container_registry_enabled": True,
+ "container_expiration_policy": {
+ "cadence": "7d",
+ "enabled": True,
+ "keep_n": None,
+ "older_than": None,
+ "name_regex": None,
+ "name_regex_keep": None,
+ "next_run_at": "2020-05-04T06:13:22.654Z",
+ },
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": True,
+ "can_create_merge_request_in": True,
+ "issues_access_level": "enabled",
+ "repository_access_level": "enabled",
+ "merge_requests_access_level": "enabled",
+ "forking_access_level": "enabled",
+ "wiki_access_level": "enabled",
+ "builds_access_level": "enabled",
+ "snippets_access_level": "enabled",
+ "pages_access_level": "enabled",
+ "security_and_compliance_access_level": "enabled",
+ "emails_disabled": None,
+ "emails_enabled": None,
+ "shared_runners_enabled": True,
+ "lfs_enabled": True,
+ "creator_id": 1,
+ "import_status": "failed",
+ "open_issues_count": 10,
+ "ci_default_git_depth": 50,
+ "ci_forward_deployment_enabled": True,
+ "ci_forward_deployment_rollback_allowed": True,
+ "ci_allow_fork_pipelines_to_run_in_parent_project": True,
+ "public_jobs": True,
+ "build_timeout": 3600,
+ "auto_cancel_pending_pipelines": "enabled",
+ "ci_config_path": None,
+ "shared_with_groups": [
+ {
+ "group_id": 24,
+ "group_name": "Commit451",
+ "group_full_path": "Commit451",
+ "group_access_level": 30,
+ "expires_at": None,
+ }
+ ],
+ "only_allow_merge_if_pipeline_succeeds": False,
+ "request_access_enabled": True,
+ "only_allow_merge_if_all_discussions_are_resolved": False,
+ "remove_source_branch_after_merge": True,
+ "printing_merge_request_link_enabled": True,
+ "merge_method": "merge",
+ "suggestion_commit_message": None,
+ "auto_devops_enabled": True,
+ "auto_devops_deploy_strategy": "continuous",
+ "autoclose_referenced_issues": True,
+ "repository_storage": "default",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Projects"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_7():
+ # Details of a group
+ example_data = {
+ "id": 4,
+ "name": "Twitter",
+ "path": "twitter",
+ "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
+ "visibility": "public",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/groups/twitter",
+ "request_access_enabled": False,
+ "repository_storage": "default",
+ "full_name": "Twitter",
+ "full_path": "twitter",
+ "runners_token": "ba324ca7b1c77fc20bb9",
+ "file_template_project_id": 1,
+ "parent_id": None,
+ "enabled_git_access_protocol": "all",
+ "created_at": "2020-01-15T12:36:29.590Z",
+ "shared_with_groups": [
+ {
+ "group_id": 28,
+ "group_name": "H5bp",
+ "group_full_path": "h5bp",
+ "group_access_level": 20,
+ "expires_at": None,
+ }
+ ],
+ "prevent_sharing_groups_outside_hierarchy": False,
+ "projects": [
+ {
+ "id": 7,
+ "description": "Voluptas veniam qui et beatae voluptas doloremque explicabo facilis.",
+ "default_branch": "main",
+ "tag_list": [],
+ "topics": [],
+ "archived": False,
+ "visibility": "public",
+ "ssh_url_to_repo": "git@gitlab.example.com:twitter/typeahead-js.git",
+ "http_url_to_repo": "https://gitlab.example.com/twitter/typeahead-js.git",
+ "web_url": "https://gitlab.example.com/twitter/typeahead-js",
+ "name": "Typeahead.Js",
+ "name_with_namespace": "Twitter / Typeahead.Js",
+ "path": "typeahead-js",
+ "path_with_namespace": "twitter/typeahead-js",
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": False,
+ "container_registry_enabled": True,
+ "created_at": "2016-06-17T07:47:25.578Z",
+ "last_activity_at": "2016-06-17T07:47:25.881Z",
+ "shared_runners_enabled": True,
+ "creator_id": 1,
+ "namespace": {
+ "id": 4,
+ "name": "Twitter",
+ "path": "twitter",
+ "kind": "group",
+ },
+ "avatar_url": None,
+ "star_count": 0,
+ "forks_count": 0,
+ "open_issues_count": 3,
+ "public_jobs": True,
+ "shared_with_groups": [],
+ "request_access_enabled": False,
+ },
+ {
+ "id": 6,
+ "description": "Aspernatur omnis repudiandae qui voluptatibus eaque.",
+ "default_branch": "main",
+ "tag_list": [],
+ "topics": [],
+ "archived": False,
+ "visibility": "internal",
+ "ssh_url_to_repo": "git@gitlab.example.com:twitter/flight.git",
+ "http_url_to_repo": "https://gitlab.example.com/twitter/flight.git",
+ "web_url": "https://gitlab.example.com/twitter/flight",
+ "name": "Flight",
+ "name_with_namespace": "Twitter / Flight",
+ "path": "flight",
+ "path_with_namespace": "twitter/flight",
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": False,
+ "container_registry_enabled": True,
+ "created_at": "2016-06-17T07:47:24.661Z",
+ "last_activity_at": "2016-06-17T07:47:24.838Z",
+ "shared_runners_enabled": True,
+ "creator_id": 1,
+ "namespace": {
+ "id": 4,
+ "name": "Twitter",
+ "path": "twitter",
+ "kind": "group",
+ },
+ "avatar_url": None,
+ "star_count": 0,
+ "forks_count": 0,
+ "open_issues_count": 8,
+ "public_jobs": True,
+ "shared_with_groups": [],
+ "request_access_enabled": False,
+ },
+ ],
+ "shared_projects": [
+ {
+ "id": 8,
+ "description": "Velit eveniet provident fugiat saepe eligendi autem.",
+ "default_branch": "main",
+ "tag_list": [],
+ "topics": [],
+ "archived": False,
+ "visibility": "private",
+ "ssh_url_to_repo": "git@gitlab.example.com:h5bp/html5-boilerplate.git",
+ "http_url_to_repo": "https://gitlab.example.com/h5bp/html5-boilerplate.git",
+ "web_url": "https://gitlab.example.com/h5bp/html5-boilerplate",
+ "name": "Html5 Boilerplate",
+ "name_with_namespace": "H5bp / Html5 Boilerplate",
+ "path": "html5-boilerplate",
+ "path_with_namespace": "h5bp/html5-boilerplate",
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": False,
+ "container_registry_enabled": True,
+ "created_at": "2016-06-17T07:47:27.089Z",
+ "last_activity_at": "2016-06-17T07:47:27.310Z",
+ "shared_runners_enabled": True,
+ "creator_id": 1,
+ "namespace": {"id": 5, "name": "H5bp", "path": "h5bp", "kind": "group"},
+ "avatar_url": None,
+ "star_count": 0,
+ "forks_count": 0,
+ "open_issues_count": 4,
+ "public_jobs": True,
+ "shared_with_groups": [
+ {
+ "group_id": 4,
+ "group_name": "Twitter",
+ "group_full_path": "twitter",
+ "group_access_level": 30,
+ "expires_at": None,
+ },
+ {
+ "group_id": 3,
+ "group_name": "Gitlab Org",
+ "group_full_path": "gitlab-org",
+ "group_access_level": 10,
+ "expires_at": "2018-08-14",
+ },
+ ],
+ }
+ ],
+ "ip_restriction_ranges": None,
+ "math_rendering_limits_enabled": True,
+ "lock_math_rendering_limits_enabled": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Group"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_8():
+ # Details of a group
+ example_data = {
+ "id": 4,
+ "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
+ "shared_runners_minutes_limit": 133,
+ "extra_shared_runners_minutes_limit": 133,
+ "marked_for_deletion_on": "2020-04-03",
+ "membership_lock": False,
+ "wiki_access_level": "disabled",
+ "duo_features_enabled": True,
+ "lock_duo_features_enabled": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Group"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_9():
+ # Details of a group
+ example_data = {
+ "id": 4,
+ "name": "Twitter",
+ "path": "twitter",
+ "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
+ "visibility": "public",
+ "avatar_url": None,
+ "web_url": "https://gitlab.example.com/groups/twitter",
+ "request_access_enabled": False,
+ "repository_storage": "default",
+ "full_name": "Twitter",
+ "full_path": "twitter",
+ "file_template_project_id": 1,
+ "parent_id": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Group"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_10():
+ # Get groups to which a user can transfer a group
+ example_data = [
+ {
+ "id": 27,
+ "web_url": "https://gitlab.example.com/groups/gitlab",
+ "name": "GitLab",
+ "avatar_url": None,
+ "full_name": "GitLab",
+ "full_path": "GitLab",
+ },
+ {
+ "id": 31,
+ "web_url": "https://gitlab.example.com/groups/foobar",
+ "name": "FooBar",
+ "avatar_url": None,
+ "full_name": "FooBar",
+ "full_path": "FooBar",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Groups"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_11():
+ # Update group
+ example_data = {
+ "id": 5,
+ "name": "Experimental",
+ "path": "h5bp",
+ "description": "foo",
+ "visibility": "internal",
+ "avatar_url": None,
+ "web_url": "http://gitlab.example.com/groups/h5bp",
+ "request_access_enabled": False,
+ "repository_storage": "default",
+ "full_name": "Foobar Group",
+ "full_path": "h5bp",
+ "file_template_project_id": 1,
+ "parent_id": None,
+ "enabled_git_access_protocol": "all",
+ "created_at": "2020-01-15T12:36:29.590Z",
+ "prevent_sharing_groups_outside_hierarchy": False,
+ "projects": [
+ {
+ "id": 9,
+ "description": "foo",
+ "default_branch": "main",
+ "tag_list": [],
+ "topics": [],
+ "public": False,
+ "archived": False,
+ "visibility": "internal",
+ "ssh_url_to_repo": "git@gitlab.example.com/html5-boilerplate.git",
+ "http_url_to_repo": "http://gitlab.example.com/h5bp/html5-boilerplate.git",
+ "web_url": "http://gitlab.example.com/h5bp/html5-boilerplate",
+ "name": "Html5 Boilerplate",
+ "name_with_namespace": "Experimental / Html5 Boilerplate",
+ "path": "html5-boilerplate",
+ "path_with_namespace": "h5bp/html5-boilerplate",
+ "issues_enabled": True,
+ "merge_requests_enabled": True,
+ "wiki_enabled": True,
+ "jobs_enabled": True,
+ "snippets_enabled": True,
+ "created_at": "2016-04-05T21:40:50.169Z",
+ "last_activity_at": "2016-04-06T16:52:08.432Z",
+ "shared_runners_enabled": True,
+ "creator_id": 1,
+ "namespace": {
+ "id": 5,
+ "name": "Experimental",
+ "path": "h5bp",
+ "kind": "group",
+ },
+ "avatar_url": None,
+ "star_count": 1,
+ "forks_count": 0,
+ "open_issues_count": 3,
+ "public_jobs": True,
+ "shared_with_groups": [],
+ "request_access_enabled": False,
+ }
+ ],
+ "ip_restriction_ranges": None,
+ "math_rendering_limits_enabled": True,
+ "lock_math_rendering_limits_enabled": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Group"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_12():
+ # Search for a group
+ example_data = [
+ {
+ "id": 1,
+ "name": "Foobar Group",
+ "path": "foo-bar",
+ "description": "An interesting group",
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Projects"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_13():
+ # List provisioned users
+ example_data = [
+ {
+ "id": 66,
+ "username": "user22",
+ "name": "John Doe22",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/xxx?s=80&d=identicon",
+ "web_url": "http://my.gitlab.com/user22",
+ "created_at": "2021-09-10T12:48:22.381Z",
+ "bio": "",
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": None,
+ "job_title": "",
+ "pronouns": None,
+ "bot": False,
+ "work_information": None,
+ "followers": 0,
+ "following": 0,
+ "local_time": None,
+ "last_sign_in_at": None,
+ "confirmed_at": "2021-09-10T12:48:22.330Z",
+ "last_activity_on": None,
+ "email": "user22@example.org",
+ "theme_id": 1,
+ "color_scheme_id": 1,
+ "projects_limit": 100000,
+ "current_sign_in_at": None,
+ "identities": [],
+ "can_create_group": True,
+ "can_create_project": True,
+ "two_factor_enabled": False,
+ "external": False,
+ "private_profile": False,
+ "commit_email": "user22@example.org",
+ "shared_runners_minutes_limit": None,
+ "extra_shared_runners_minutes_limit": None,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_14():
+ # List group users
+ example_data = [
+ {
+ "id": 66,
+ "username": "user22",
+ "name": "John Doe22",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/xxx?s=80&d=identicon",
+ "web_url": "http://my.gitlab.com/user22",
+ "created_at": "2021-09-10T12:48:22.381Z",
+ "bio": "",
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": None,
+ "job_title": "",
+ "pronouns": None,
+ "bot": False,
+ "work_information": None,
+ "followers": 0,
+ "following": 0,
+ "local_time": None,
+ "last_sign_in_at": None,
+ "confirmed_at": "2021-09-10T12:48:22.330Z",
+ "last_activity_on": None,
+ "email": "user22@example.org",
+ "theme_id": 1,
+ "color_scheme_id": 1,
+ "projects_limit": 100000,
+ "current_sign_in_at": None,
+ "identities": [],
+ "can_create_group": True,
+ "can_create_project": True,
+ "two_factor_enabled": False,
+ "external": False,
+ "private_profile": False,
+ "commit_email": "user22@example.org",
+ "shared_runners_minutes_limit": None,
+ "extra_shared_runners_minutes_limit": None,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_15():
+ # Create Service Account User
+ example_data = {
+ "id": 57,
+ "username": "service_account_group_345_6018816a18e515214e0c34c2b33523fc",
+ "name": "Service account user",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployToken"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_16():
+ # Create Personal Access Token for Service Account User
+ example_data = {
+ "id": 6,
+ "name": "service_accounts_token",
+ "revoked": False,
+ "created_at": "2023-06-13T07:47:13.900Z",
+ "scopes": ["api"],
+ "user_id": 71,
+ "last_used_at": None,
+ "active": True,
+ "expires_at": "2024-06-12",
+ "token": "",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployToken"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_17():
+ # Rotate a Personal Access Token for Service Account User
+ example_data = {
+ "id": 7,
+ "name": "service_accounts_token",
+ "revoked": False,
+ "created_at": "2023-06-13T07:54:49.962Z",
+ "scopes": ["api"],
+ "user_id": 71,
+ "last_used_at": None,
+ "active": True,
+ "expires_at": "2023-06-20",
+ "token": "",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "DeployToken"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_18():
+ # Get group hook
+ example_data = {
+ "id": 1,
+ "url": "http://example.com/hook",
+ "name": "Hook name",
+ "description": "Hook description",
+ "group_id": 3,
+ "push_events": True,
+ "push_events_branch_filter": "",
+ "issues_events": True,
+ "confidential_issues_events": True,
+ "merge_requests_events": True,
+ "tag_push_events": True,
+ "note_events": True,
+ "confidential_note_events": True,
+ "job_events": True,
+ "pipeline_events": True,
+ "wiki_page_events": True,
+ "deployment_events": True,
+ "releases_events": True,
+ "subgroup_events": True,
+ "member_events": True,
+ "enable_ssl_verification": True,
+ "repository_update_events": False,
+ "alert_status": "executable",
+ "disabled_until": None,
+ "url_variables": [],
+ "created_at": "2012-10-12T17:04:47Z",
+ "resource_access_token_events": True,
+ "custom_webhook_template": '{"event":"{{object_kind}}"}',
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Webhook"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_19():
+ # Push Rules
+ example_data = {
+ "id": 2,
+ "created_at": "2020-08-17T19:09:19.580Z",
+ "commit_committer_check": True,
+ "commit_committer_name_check": True,
+ "reject_unsigned_commits": False,
+ "commit_message_regex": "[a-zA-Z]",
+ "commit_message_negative_regex": "[x+]",
+ "branch_name_regex": "[a-z]",
+ "deny_delete_tag": True,
+ "member_check": True,
+ "prevent_secrets": True,
+ "author_email_regex": "^[A-Za-z0-9.]+@gitlab.com$",
+ "file_name_regex": "(exe)$",
+ "max_file_size": 100,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Rule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_20():
+ # Add SAML group link
+ example_data = {"name": "saml-group-1", "access_level": 10, "member_role_id": 12}
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "AccessControl"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_group_response_21():
+ # Get saml group link
+ example_data = {"name": "saml-group-1", "access_level": 10, "member_role_id": 12}
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "AccessControl"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_1():
+ # List project jobs
+ example_data = [
+ {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.802Z",
+ "started_at": "2015-12-24T17:54:27.722Z",
+ "finished_at": "2015-12-24T17:54:27.895Z",
+ "erased_at": None,
+ "duration": 0.173,
+ "queued_duration": 0.010,
+ "artifacts_file": {"filename": "artifacts.zip", "size": 1000},
+ "artifacts": [
+ {
+ "file_type": "archive",
+ "size": 1000,
+ "filename": "artifacts.zip",
+ "file_format": "zip",
+ },
+ {
+ "file_type": "metadata",
+ "size": 186,
+ "filename": "metadata.gz",
+ "file_format": "gzip",
+ },
+ {
+ "file_type": "trace",
+ "size": 1500,
+ "filename": "job.log",
+ "file_format": "raw",
+ },
+ {
+ "file_type": "junit",
+ "size": 750,
+ "filename": "junit.xml.gz",
+ "file_format": "gzip",
+ },
+ ],
+ "artifacts_expire_at": "2016-01-23T17:54:27.895Z",
+ "tag_list": ["docker runner", "ubuntu18"],
+ "id": 7,
+ "name": "teaspoon",
+ "pipeline": {
+ "id": 6,
+ "project_id": 1,
+ "ref": "main",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ },
+ "ref": "main",
+ "runner": {
+ "id": 32,
+ "description": "",
+ "ip_address": None,
+ "active": True,
+ "paused": False,
+ "is_shared": True,
+ "runner_type": "instance_type",
+ "name": None,
+ "online": False,
+ "status": "offline",
+ },
+ "runner_manager": {
+ "id": 1,
+ "system_id": "s_89e5e9956577",
+ "version": "16.11.1",
+ "revision": "535ced5f",
+ "platform": "linux",
+ "architecture": "amd64",
+ "created_at": "2024-05-01T10:12:02.507Z",
+ "contacted_at": "2024-05-07T06:30:09.355Z",
+ "ip_address": "127.0.0.1",
+ "status": "offline",
+ },
+ "stage": "test",
+ "status": "failed",
+ "failure_reason": "script_failure",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/7",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ },
+ {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.727Z",
+ "started_at": "2015-12-24T17:54:24.729Z",
+ "finished_at": "2015-12-24T17:54:24.921Z",
+ "erased_at": None,
+ "duration": 0.192,
+ "queued_duration": 0.023,
+ "artifacts_expire_at": "2016-01-23T17:54:24.921Z",
+ "tag_list": ["docker runner", "win10-2004"],
+ "id": 6,
+ "name": "rspec:other",
+ "pipeline": {
+ "id": 6,
+ "project_id": 1,
+ "ref": "main",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ },
+ "ref": "main",
+ "artifacts": [],
+ "runner": None,
+ "runner_manager": None,
+ "stage": "test",
+ "status": "failed",
+ "failure_reason": "stuck_or_timeout_failure",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/6",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Jobs"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_2():
+ # List pipeline jobs
+ example_data = [
+ {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.727Z",
+ "started_at": "2015-12-24T17:54:24.729Z",
+ "finished_at": "2015-12-24T17:54:24.921Z",
+ "erased_at": None,
+ "duration": 0.192,
+ "queued_duration": 0.023,
+ "artifacts_expire_at": "2016-01-23T17:54:24.921Z",
+ "tag_list": ["docker runner", "ubuntu18"],
+ "id": 6,
+ "name": "rspec:other",
+ "pipeline": {
+ "id": 6,
+ "project_id": 1,
+ "ref": "main",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ },
+ "ref": "main",
+ "artifacts": [],
+ "runner": {
+ "id": 32,
+ "description": "",
+ "ip_address": None,
+ "active": True,
+ "paused": False,
+ "is_shared": True,
+ "runner_type": "instance_type",
+ "name": None,
+ "online": False,
+ "status": "offline",
+ },
+ "runner_manager": {
+ "id": 1,
+ "system_id": "s_89e5e9956577",
+ "version": "16.11.1",
+ "revision": "535ced5f",
+ "platform": "linux",
+ "architecture": "amd64",
+ "created_at": "2024-05-01T10:12:02.507Z",
+ "contacted_at": "2024-05-07T06:30:09.355Z",
+ "ip_address": "127.0.0.1",
+ },
+ "stage": "test",
+ "status": "failed",
+ "failure_reason": "stuck_or_timeout_failure",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/6",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ },
+ {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.802Z",
+ "started_at": "2015-12-24T17:54:27.722Z",
+ "finished_at": "2015-12-24T17:54:27.895Z",
+ "erased_at": None,
+ "duration": 0.173,
+ "queued_duration": 0.023,
+ "artifacts_file": {"filename": "artifacts.zip", "size": 1000},
+ "artifacts": [
+ {
+ "file_type": "archive",
+ "size": 1000,
+ "filename": "artifacts.zip",
+ "file_format": "zip",
+ },
+ {
+ "file_type": "metadata",
+ "size": 186,
+ "filename": "metadata.gz",
+ "file_format": "gzip",
+ },
+ {
+ "file_type": "trace",
+ "size": 1500,
+ "filename": "job.log",
+ "file_format": "raw",
+ },
+ {
+ "file_type": "junit",
+ "size": 750,
+ "filename": "junit.xml.gz",
+ "file_format": "gzip",
+ },
+ ],
+ "artifacts_expire_at": "2016-01-23T17:54:27.895Z",
+ "tag_list": ["docker runner", "ubuntu18"],
+ "id": 7,
+ "name": "teaspoon",
+ "pipeline": {
+ "id": 6,
+ "project_id": 1,
+ "ref": "main",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ },
+ "ref": "main",
+ "runner": None,
+ "runner_manager": None,
+ "stage": "test",
+ "status": "failed",
+ "failure_reason": "script_failure",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/7",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Jobs"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_3():
+ # List pipeline trigger jobs
+ example_data = [
+ {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.802Z",
+ "started_at": "2015-12-24T17:54:27.722Z",
+ "finished_at": "2015-12-24T17:58:27.895Z",
+ "erased_at": None,
+ "duration": 240,
+ "queued_duration": 0.123,
+ "id": 7,
+ "name": "teaspoon",
+ "pipeline": {
+ "id": 6,
+ "project_id": 1,
+ "ref": "main",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ "created_at": "2015-12-24T15:50:16.123Z",
+ "updated_at": "2015-12-24T18:00:44.432Z",
+ "web_url": "https://example.com/foo/bar/pipelines/6",
+ },
+ "ref": "main",
+ "stage": "test",
+ "status": "pending",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/7",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ "downstream_pipeline": {
+ "id": 5,
+ "sha": "f62a4b2fb89754372a346f24659212eb8da13601",
+ "ref": "main",
+ "status": "pending",
+ "created_at": "2015-12-24T17:54:27.722Z",
+ "updated_at": "2015-12-24T17:58:27.896Z",
+ "web_url": "https://example.com/diaspora/diaspora-client/pipelines/5",
+ },
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Jobs"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_4():
+ # Get job token’s job
+ example_data = {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.880Z",
+ "started_at": "2015-12-24T17:54:30.733Z",
+ "finished_at": "2015-12-24T17:54:31.198Z",
+ "erased_at": None,
+ "duration": 0.465,
+ "queued_duration": 0.123,
+ "artifacts_expire_at": "2016-01-23T17:54:31.198Z",
+ "id": 8,
+ "name": "rubocop",
+ "pipeline": {
+ "id": 6,
+ "project_id": 1,
+ "ref": "main",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ },
+ "ref": "main",
+ "artifacts": [],
+ "runner": None,
+ "runner_manager": None,
+ "stage": "test",
+ "status": "failed",
+ "failure_reason": "script_failure",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/8",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Job"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_5():
+ # Get GitLab agent by CI_JOB_TOKEN
+ example_data = {
+ "allowed_agents": [
+ {
+ "id": 1,
+ "config_project": {
+ "id": 1,
+ "description": None,
+ "name": "project1",
+ "name_with_namespace": "John Doe2 / project1",
+ "path": "project1",
+ "path_with_namespace": "namespace1/project1",
+ "created_at": "2022-11-16T14:51:50.579Z",
+ },
+ }
+ ],
+ "job": {"id": 1},
+ "pipeline": {"id": 2},
+ "project": {"id": 1, "groups": [{"id": 1}, {"id": 2}, {"id": 3}]},
+ "user": {
+ "id": 2,
+ "name": "John Doe3",
+ "username": "user2",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/10fc7f102b",
+ "web_url": "http://localhost/user2",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Agents"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_6():
+ example_data = {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.880Z",
+ "started_at": "2015-12-24T17:54:30.733Z",
+ "finished_at": "2015-12-24T17:54:31.198Z",
+ "erased_at": None,
+ "duration": 0.465,
+ "queued_duration": 0.010,
+ "artifacts_expire_at": "2016-01-23T17:54:31.198Z",
+ "tag_list": ["docker runner", "macos-10.15"],
+ "id": 8,
+ "name": "rubocop",
+ "pipeline": {
+ "id": 6,
+ "project_id": 1,
+ "ref": "main",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ },
+ "ref": "main",
+ "artifacts": [],
+ "runner": None,
+ "runner_manager": None,
+ "stage": "test",
+ "status": "failed",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/8",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Job"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_7():
+ # Cancel a job
+ example_data = {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2016-01-11T10:13:33.506Z",
+ "started_at": "2016-01-11T10:14:09.526Z",
+ "finished_at": None,
+ "erased_at": None,
+ "duration": 8,
+ "queued_duration": 0.010,
+ "id": 1,
+ "name": "rubocop",
+ "ref": "main",
+ "artifacts": [],
+ "runner": None,
+ "runner_manager": None,
+ "stage": "test",
+ "status": "canceled",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/1",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Job"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_8():
+ # Retry a job
+ example_data = {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2016-01-11T10:13:33.506Z",
+ "started_at": None,
+ "finished_at": None,
+ "erased_at": None,
+ "duration": None,
+ "queued_duration": 0.010,
+ "id": 1,
+ "name": "rubocop",
+ "ref": "main",
+ "artifacts": [],
+ "runner": None,
+ "runner_manager": None,
+ "stage": "test",
+ "status": "pending",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/1",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Job"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_jobs_response_9():
+ # Run a job
+ example_data = {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "coverage": None,
+ "archived": False,
+ "allow_failure": False,
+ "created_at": "2016-01-11T10:13:33.506Z",
+ "started_at": None,
+ "finished_at": None,
+ "erased_at": None,
+ "duration": None,
+ "queued_duration": 0.010,
+ "id": 1,
+ "name": "rubocop",
+ "ref": "main",
+ "artifacts": [],
+ "runner": None,
+ "runner_manager": None,
+ "stage": "test",
+ "status": "pending",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/1",
+ "project": {"ci_job_token_scope_enabled": False},
+ "user": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Job"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_1():
+ # List all members of a group or project
+ example_data = [
+ {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "created_at": "2012-09-22T14:13:35Z",
+ "created_by": {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "expires_at": "2012-10-22T14:13:35Z",
+ "access_level": 30,
+ "group_saml_identity": None,
+ },
+ {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "created_at": "2012-09-22T14:13:35Z",
+ "created_by": {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "expires_at": "2012-10-22T14:13:35Z",
+ "access_level": 30,
+ "email": "john@example.com",
+ "group_saml_identity": {
+ "extern_uid": "ABC-1234567890",
+ "provider": "group_saml",
+ "saml_provider_id": 10,
+ },
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_2():
+ # List all members of a group or project including inherited and invited members
+ example_data = [
+ {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "created_at": "2012-09-22T14:13:35Z",
+ "created_by": {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "expires_at": "2012-10-22T14:13:35Z",
+ "access_level": 30,
+ "group_saml_identity": None,
+ },
+ {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "created_at": "2012-09-22T14:13:35Z",
+ "created_by": {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "expires_at": "2012-10-22T14:13:35Z",
+ "access_level": 30,
+ "email": "john@example.com",
+ "group_saml_identity": {
+ "extern_uid": "ABC-1234567890",
+ "provider": "group_saml",
+ "saml_provider_id": 10,
+ },
+ },
+ {
+ "id": 3,
+ "username": "foo_bar",
+ "name": "Foo bar",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "created_at": "2012-10-22T14:13:35Z",
+ "created_by": {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "expires_at": "2012-11-22T14:13:35Z",
+ "access_level": 30,
+ "group_saml_identity": None,
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_3():
+ # Get a member of a group or project
+ example_data = {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "access_level": 30,
+ "email": "john@example.com",
+ "created_at": "2012-10-22T14:13:35Z",
+ "created_by": {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "expires_at": None,
+ "group_saml_identity": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "User"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_4():
+ # Get a member of a group or project, including inherited and invited members
+ example_data = {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "access_level": 30,
+ "created_at": "2012-10-22T14:13:35Z",
+ "created_by": {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "email": "john@example.com",
+ "expires_at": None,
+ "group_saml_identity": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "User"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_5():
+ #
+ example_data = [
+ {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "last_activity_on": "2021-01-27",
+ "membership_type": "group_member",
+ "removable": True,
+ "created_at": "2021-01-03T12:16:02.000Z",
+ "last_login_at": "2022-10-09T01:33:06.000Z",
+ },
+ {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "email": "john@example.com",
+ "last_activity_on": "2021-01-25",
+ "membership_type": "group_member",
+ "removable": True,
+ "created_at": "2021-01-04T18:46:42.000Z",
+ "last_login_at": "2022-09-29T22:18:46.000Z",
+ },
+ {
+ "id": 3,
+ "username": "foo_bar",
+ "name": "Foo bar",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "last_activity_on": "2021-01-20",
+ "membership_type": "group_invite",
+ "removable": False,
+ "created_at": "2021-01-09T07:12:31.000Z",
+ "last_login_at": "2022-10-10T07:28:56.000Z",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_6():
+ # List memberships for a billable member of a group
+ example_data = [
+ {
+ "id": 168,
+ "source_id": 131,
+ "source_full_name": "Root Group / Sub Group One",
+ "source_members_url": "https://gitlab.example.com/groups/root-group/sub-group-one/-/group_members",
+ "created_at": "2021-03-31T17:28:44.812Z",
+ "expires_at": "2022-03-21",
+ "access_level": {"string_value": "Developer", "integer_value": 30},
+ },
+ {
+ "id": 169,
+ "source_id": 63,
+ "source_full_name": "Root Group / Sub Group One / My Project",
+ "source_members_url": "https://gitlab.example.com/root-group/sub-group-one/my-project/-/project_members",
+ "created_at": "2021-03-31T17:29:14.934Z",
+ "expires_at": None,
+ "access_level": {"string_value": "Maintainer", "integer_value": 40},
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Memberships"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_7():
+ # Add a member to a group or project
+ example_data = {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "created_at": "2012-10-22T14:13:35Z",
+ "created_by": {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ "expires_at": "2012-10-22T14:13:35Z",
+ "access_level": 30,
+ "email": "john@example.com",
+ "group_saml_identity": None,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "User"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_member_response_8():
+ # List pending members of a group and its subgroups and projects
+ example_data = [
+ {
+ "id": 168,
+ "name": "Alex Garcia",
+ "username": "alex_garcia",
+ "email": "alex@example.com",
+ "avatar_url": "http://example.com/uploads/user/avatar/1/cd8.jpeg",
+ "web_url": "http://example.com/alex_garcia",
+ "approved": False,
+ "invited": False,
+ },
+ {
+ "id": 169,
+ "email": "sidney@example.com",
+ "avatar_url": "http://gravatar.com/../e346561cd8.jpeg",
+ "approved": False,
+ "invited": True,
+ },
+ {
+ "id": 170,
+ "email": "zhang@example.com",
+ "avatar_url": "http://gravatar.com/../e32131cd8.jpeg",
+ "approved": True,
+ "invited": True,
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Users"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_1():
+ # Get group-level approval rules
+ example_data = [
+ {
+ "id": 2,
+ "name": "rule1",
+ "rule_type": "any_approver",
+ "eligible_approvers": [],
+ "approvals_required": 3,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [],
+ "applies_to_all_protected_branches": True,
+ },
+ {
+ "id": 3,
+ "name": "rule2",
+ "rule_type": "code_owner",
+ "eligible_approvers": [],
+ "approvals_required": 2,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [],
+ "applies_to_all_protected_branches": True,
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRules"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_2():
+ # Create group-level approval rules
+ example_data = {
+ "id": 5,
+ "name": "security",
+ "rule_type": "any_approver",
+ "eligible_approvers": [],
+ "approvals_required": 2,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [
+ {
+ "id": 5,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "deploy_key_id": None,
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "allow_force_push": False,
+ "unprotect_access_levels": [],
+ "code_owner_approval_required": False,
+ "inherited": False,
+ }
+ ],
+ "applies_to_all_protected_branches": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_3():
+ # Update group-level approval rules
+ example_data = {
+ "id": 5,
+ "name": "security2",
+ "rule_type": "any_approver",
+ "eligible_approvers": [],
+ "approvals_required": 1,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [
+ {
+ "id": 5,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "deploy_key_id": None,
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "allow_force_push": False,
+ "unprotect_access_levels": [],
+ "code_owner_approval_required": False,
+ "inherited": False,
+ }
+ ],
+ "applies_to_all_protected_branches": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_4():
+ # Change configuration
+ example_data = {
+ "approvals_before_merge": 2,
+ "reset_approvals_on_push": True,
+ "selective_code_owner_removals": False,
+ "disable_overriding_approvers_per_merge_request": False,
+ "merge_requests_author_approval": False,
+ "merge_requests_disable_committers_approval": False,
+ "require_password_to_approve": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeApprovals"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_5():
+ # Project-level MR approvals
+ example_data = {
+ "approvers": [],
+ "approver_groups": [],
+ "approvals_before_merge": 2,
+ "reset_approvals_on_push": True,
+ "selective_code_owner_removals": False,
+ "disable_overriding_approvers_per_merge_request": False,
+ "merge_requests_author_approval": True,
+ "merge_requests_disable_committers_approval": False,
+ "require_password_to_approve": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeApprovals"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_6():
+ # Get project-level rules
+ example_data = [
+ {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRules"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_7():
+ # Get a single project-level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_8():
+ # Create project-level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 1,
+ "users": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_9():
+ # Update Project level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 1,
+ "users": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_10():
+ # Merge request-level MR approvals
+ example_data = {
+ "id": 5,
+ "iid": 5,
+ "project_id": 1,
+ "title": "Approvals API",
+ "description": "Test",
+ "state": "opened",
+ "created_at": "2016-06-08T00:19:52.638Z",
+ "updated_at": "2016-06-08T21:20:42.470Z",
+ "merge_status": "cannot_be_merged",
+ "approvals_required": 2,
+ "approvals_left": 1,
+ "approved_by": [
+ {
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "http://localhost:3000/root",
+ }
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_11():
+ # Get the approval state of merge requests
+ example_data = {
+ "approval_rules_overwritten": True,
+ "rules": [
+ {
+ "id": 1,
+ "name": "Ruby",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 4,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "approvals_required": 2,
+ "users": [
+ {
+ "id": 4,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "approved_by": [
+ {
+ "id": 4,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "source_rule": None,
+ "approved": True,
+ "overridden": False,
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_12():
+ # Get merge request level rules
+ example_data = [
+ {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "source_rule": None,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "contains_hidden_groups": False,
+ "overridden": False,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRules"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_13():
+ # Get a single merge request level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "source_rule": None,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "contains_hidden_groups": False,
+ "overridden": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_14():
+ # Create merge request level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 1,
+ "source_rule": None,
+ "users": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "contains_hidden_groups": False,
+ "overridden": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_approval_rule_response_15():
+ # Approve merge request
+ example_data = {
+ "id": 5,
+ "iid": 5,
+ "project_id": 1,
+ "title": "Approvals API",
+ "description": "Test",
+ "state": "opened",
+ "created_at": "2016-06-08T00:19:52.638Z",
+ "updated_at": "2016-06-09T21:32:14.105Z",
+ "merge_status": "can_be_merged",
+ "approvals_required": 2,
+ "approvals_left": 0,
+ "approved_by": [
+ {
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "http://localhost:3000/root",
+ }
+ },
+ {
+ "user": {
+ "name": "Nico Cartwright",
+ "username": "ryley",
+ "id": 2,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/cf7ad14b34162a76d593e3affca2adca?s=80\u0026d=identicon",
+ "web_url": "http://localhost:3000/ryley",
+ }
+ },
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_1():
+ # Get group-level approval rules
+ example_data = [
+ {
+ "id": 2,
+ "name": "rule1",
+ "rule_type": "any_approver",
+ "eligible_approvers": [],
+ "approvals_required": 3,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [],
+ "applies_to_all_protected_branches": True,
+ },
+ {
+ "id": 3,
+ "name": "rule2",
+ "rule_type": "code_owner",
+ "eligible_approvers": [],
+ "approvals_required": 2,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [],
+ "applies_to_all_protected_branches": True,
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRules"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_2():
+ # Create group-level approval rules
+ example_data = {
+ "id": 5,
+ "name": "security",
+ "rule_type": "any_approver",
+ "eligible_approvers": [],
+ "approvals_required": 2,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [
+ {
+ "id": 5,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "deploy_key_id": None,
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "allow_force_push": False,
+ "unprotect_access_levels": [],
+ "code_owner_approval_required": False,
+ "inherited": False,
+ }
+ ],
+ "applies_to_all_protected_branches": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_3():
+ # Update group-level approval rules
+ example_data = {
+ "id": 5,
+ "name": "security2",
+ "rule_type": "any_approver",
+ "eligible_approvers": [],
+ "approvals_required": 1,
+ "users": [],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "protected_branches": [
+ {
+ "id": 5,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "deploy_key_id": None,
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "id": 5,
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": None,
+ "group_id": None,
+ }
+ ],
+ "allow_force_push": False,
+ "unprotect_access_levels": [],
+ "code_owner_approval_required": False,
+ "inherited": False,
+ }
+ ],
+ "applies_to_all_protected_branches": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_4():
+ # Change configuration
+ example_data = {
+ "approvals_before_merge": 2,
+ "reset_approvals_on_push": True,
+ "selective_code_owner_removals": False,
+ "disable_overriding_approvers_per_merge_request": False,
+ "merge_requests_author_approval": False,
+ "merge_requests_disable_committers_approval": False,
+ "require_password_to_approve": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeApprovals"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_5():
+ # Project-level MR approvals
+ example_data = {
+ "approvers": [],
+ "approver_groups": [],
+ "approvals_before_merge": 2,
+ "reset_approvals_on_push": True,
+ "selective_code_owner_removals": False,
+ "disable_overriding_approvers_per_merge_request": False,
+ "merge_requests_author_approval": True,
+ "merge_requests_disable_committers_approval": False,
+ "require_password_to_approve": True,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeApprovals"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_6():
+ # Get project-level rules
+ example_data = [
+ {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRules"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_7():
+ # Get a single project-level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_8():
+ # Create project-level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 1,
+ "users": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_9():
+ # Update Project level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 1,
+ "users": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "applies_to_all_protected_branches": False,
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "main",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ }
+ ],
+ "unprotect_access_levels": [
+ {"access_level": 40, "access_level_description": "Maintainers"}
+ ],
+ "code_owner_approval_required": "false",
+ }
+ ],
+ "contains_hidden_groups": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_10():
+ # Merge request-level MR approvals
+ example_data = {
+ "id": 5,
+ "iid": 5,
+ "project_id": 1,
+ "title": "Approvals API",
+ "description": "Test",
+ "state": "opened",
+ "created_at": "2016-06-08T00:19:52.638Z",
+ "updated_at": "2016-06-08T21:20:42.470Z",
+ "merge_status": "cannot_be_merged",
+ "approvals_required": 2,
+ "approvals_left": 1,
+ "approved_by": [
+ {
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "http://localhost:3000/root",
+ }
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_11():
+ # Get the approval state of merge requests
+ example_data = {
+ "approval_rules_overwritten": True,
+ "rules": [
+ {
+ "id": 1,
+ "name": "Ruby",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 4,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "approvals_required": 2,
+ "users": [
+ {
+ "id": 4,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [],
+ "contains_hidden_groups": False,
+ "approved_by": [
+ {
+ "id": 4,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "source_rule": None,
+ "approved": True,
+ "overridden": False,
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_12():
+ # Get merge request level rules
+ example_data = [
+ {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "source_rule": None,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "contains_hidden_groups": False,
+ "overridden": False,
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRules"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_13():
+ # Get a single merge request level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 3,
+ "source_rule": None,
+ "users": [
+ {
+ "id": 5,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "contains_hidden_groups": False,
+ "overridden": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_14():
+ # Create merge request level rule
+ example_data = {
+ "id": 1,
+ "name": "security",
+ "rule_type": "regular",
+ "eligible_approvers": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ },
+ {
+ "id": 50,
+ "name": "Group Member 1",
+ "username": "group_member_1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/group_member_1",
+ },
+ ],
+ "approvals_required": 1,
+ "source_rule": None,
+ "users": [
+ {
+ "id": 2,
+ "name": "John Doe",
+ "username": "jdoe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
+ "web_url": "http://localhost/jdoe",
+ }
+ ],
+ "groups": [
+ {
+ "id": 5,
+ "name": "group1",
+ "path": "group1",
+ "description": "",
+ "visibility": "public",
+ "lfs_enabled": False,
+ "avatar_url": None,
+ "web_url": "http://localhost/groups/group1",
+ "request_access_enabled": False,
+ "full_name": "group1",
+ "full_path": "group1",
+ "parent_id": None,
+ "ldap_cn": None,
+ "ldap_access": None,
+ }
+ ],
+ "contains_hidden_groups": False,
+ "overridden": False,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "ApprovalRule"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_protected_branch_response_15():
+ # Approve merge request
+ example_data = {
+ "id": 5,
+ "iid": 5,
+ "project_id": 1,
+ "title": "Approvals API",
+ "description": "Test",
+ "state": "opened",
+ "created_at": "2016-06-08T00:19:52.638Z",
+ "updated_at": "2016-06-09T21:32:14.105Z",
+ "merge_status": "can_be_merged",
+ "approvals_required": 2,
+ "approvals_left": 0,
+ "approved_by": [
+ {
+ "user": {
+ "name": "Administrator",
+ "username": "root",
+ "id": 1,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "http://localhost:3000/root",
+ }
+ },
+ {
+ "user": {
+ "name": "Nico Cartwright",
+ "username": "ryley",
+ "id": 2,
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/cf7ad14b34162a76d593e3affca2adca?s=80\u0026d=identicon",
+ "web_url": "http://localhost:3000/ryley",
+ }
+ },
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "MergeRequest"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_package_response_1():
+ # List packages
+ example_data = [
+ {
+ "id": 1,
+ "name": "com/mycompany/my-app",
+ "version": "1.0-SNAPSHOT",
+ "package_type": "maven",
+ "created_at": "2019-11-27T03:37:38.711Z",
+ },
+ {
+ "id": 2,
+ "name": "@foo/bar",
+ "version": "1.0.3",
+ "package_type": "npm",
+ "created_at": "2019-11-27T03:37:38.711Z",
+ },
+ {
+ "id": 3,
+ "name": "Hello/0.1@mycompany/stable",
+ "conan_package_name": "Hello",
+ "version": "0.1",
+ "package_type": "conan",
+ "_links": {
+ "web_path": "/foo/bar/-/packages/3",
+ "delete_api_path": "https://gitlab.example.com/api/v4/projects/1/packages/3",
+ },
+ "created_at": "2029-12-16T20:33:34.316Z",
+ "tags": [],
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Packages"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_package_response_2():
+
+ # Package for a group
+ example_data = [
+ {
+ "id": 1,
+ "name": "com/mycompany/my-app",
+ "version": "1.0-SNAPSHOT",
+ "package_type": "maven",
+ "_links": {
+ "web_path": "/namespace1/project1/-/packages/1",
+ "delete_api_path": "/namespace1/project1/-/packages/1",
+ },
+ "created_at": "2019-11-27T03:37:38.711Z",
+ "pipelines": [
+ {
+ "id": 123,
+ "status": "pending",
+ "ref": "new-pipeline",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "web_url": "https://example.com/foo/bar/pipelines/47",
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "user": {
+ "name": "Administrator",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ },
+ }
+ ],
+ },
+ {
+ "id": 2,
+ "name": "@foo/bar",
+ "version": "1.0.3",
+ "package_type": "npm",
+ "_links": {
+ "web_path": "/namespace1/project1/-/packages/1",
+ "delete_api_path": "/namespace1/project1/-/packages/1",
+ },
+ "created_at": "2019-11-27T03:37:38.711Z",
+ "pipelines": [
+ {
+ "id": 123,
+ "status": "pending",
+ "ref": "new-pipeline",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "web_url": "https://example.com/foo/bar/pipelines/47",
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "user": {
+ "name": "Administrator",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ },
+ }
+ ],
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Packages"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_package_response_3():
+
+ # Get a project package
+ example_data = {
+ "id": 1,
+ "name": "com/mycompany/my-app",
+ "version": "1.0-SNAPSHOT",
+ "package_type": "maven",
+ "_links": {
+ "web_path": "/namespace1/project1/-/packages/1",
+ "delete_api_path": "/namespace1/project1/-/packages/1",
+ },
+ "created_at": "2019-11-27T03:37:38.711Z",
+ "last_downloaded_at": "2022-09-07T07:51:50.504Z",
+ "pipelines": [
+ {
+ "id": 123,
+ "status": "pending",
+ "ref": "new-pipeline",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "web_url": "https://example.com/foo/bar/pipelines/47",
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "user": {
+ "name": "Administrator",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ },
+ }
+ ],
+ "versions": [
+ {
+ "id": 2,
+ "version": "2.0-SNAPSHOT",
+ "created_at": "2020-04-28T04:42:11.573Z",
+ "pipelines": [
+ {
+ "id": 234,
+ "status": "pending",
+ "ref": "new-pipeline",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "web_url": "https://example.com/foo/bar/pipelines/58",
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "user": {
+ "name": "Administrator",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ },
+ }
+ ],
+ }
+ ],
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Package"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_package_response_4():
+
+ # List package files
+ example_data = [
+ {
+ "id": 25,
+ "package_id": 4,
+ "created_at": "2018-11-07T15:25:52.199Z",
+ "file_name": "my-app-1.5-20181107.152550-1.jar",
+ "size": 2421,
+ "file_md5": "58e6a45a629910c6ff99145a688971ac",
+ "file_sha1": "ebd193463d3915d7e22219f52740056dfd26cbfe",
+ "file_sha256": "a903393463d3915d7e22219f52740056dfd26cbfeff321b",
+ "pipelines": [
+ {
+ "id": 123,
+ "status": "pending",
+ "ref": "new-pipeline",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "web_url": "https://example.com/foo/bar/pipelines/47",
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ "user": {
+ "name": "Administrator",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ },
+ }
+ ],
+ },
+ {
+ "id": 26,
+ "package_id": 4,
+ "created_at": "2018-11-07T15:25:56.776Z",
+ "file_name": "my-app-1.5-20181107.152550-1.pom",
+ "size": 1122,
+ "file_md5": "d90f11d851e17c5513586b4a7e98f1b2",
+ "file_sha1": "9608d068fe88aff85781811a42f32d97feb440b5",
+ "file_sha256": "2987d068fe88aff85781811a42f32d97feb4f092a399",
+ },
+ {
+ "id": 27,
+ "package_id": 4,
+ "created_at": "2018-11-07T15:26:00.556Z",
+ "file_name": "maven-metadata.xml",
+ "size": 767,
+ "file_md5": "6dfd0cce1203145a927fef5e3a1c650c",
+ "file_sha1": "d25932de56052d320a8ac156f745ece73f6a8cd2",
+ "file_sha256": "ac849d002e56052d320a8ac156f745ece73f6a8cd2f3e82",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Packages"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_package_response_5():
+
+ # List package pipelines
+ example_data = [
+ {
+ "id": 1,
+ "iid": 1,
+ "project_id": 9,
+ "sha": "2b6127f6bb6f475c4e81afcc2251e3f941e554f9",
+ "ref": "mytag",
+ "status": "failed",
+ "source": "push",
+ "created_at": "2023-02-01T12:19:21.895Z",
+ "updated_at": "2023-02-01T14:00:05.922Z",
+ "web_url": "http://gdk.test:3001/feature-testing/composer-repository/-/pipelines/1",
+ "user": {
+ "id": 1,
+ "username": "root",
+ "name": "Administrator",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "http://gdk.test:3001/root",
+ },
+ },
+ {
+ "id": 2,
+ "iid": 2,
+ "project_id": 9,
+ "sha": "e564015ac6cb3d8617647802c875b27d392f72a6",
+ "ref": "main",
+ "status": "canceled",
+ "source": "push",
+ "created_at": "2023-02-01T12:23:23.694Z",
+ "updated_at": "2023-02-01T12:26:28.635Z",
+ "web_url": "http://gdk.test:3001/feature-testing/composer-repository/-/pipelines/2",
+ "user": {
+ "id": 1,
+ "username": "root",
+ "name": "Administrator",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "http://gdk.test:3001/root",
+ },
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Pipelines"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_release_response_1():
+ # List Releases
+ example_data = [
+ {
+ "tag_name": "v0.2",
+ "description": "## CHANGELOG\r\n\r\n- Escape label and milestone titles to prevent XSS in GLFM autocomplete. !2740\r\n- Prevent private snippets from being embeddable.\r\n- Add subresources removal to member destroy service.",
+ "name": "Awesome app v0.2 beta",
+ "created_at": "2019-01-03T01:56:19.539Z",
+ "released_at": "2019-01-03T01:56:19.539Z",
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "commit": {
+ "id": "079e90101242458910cccd35eab0e211dfc359c0",
+ "short_id": "079e9010",
+ "title": "Update README.md",
+ "created_at": "2019-01-03T01:55:38.000Z",
+ "parent_ids": ["f8d3d94cbd347e924aa7b715845e439d00e80ca4"],
+ "message": "Update README.md",
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2019-01-03T01:55:38.000Z",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2019-01-03T01:55:38.000Z",
+ },
+ "milestones": [
+ {
+ "id": 51,
+ "iid": 1,
+ "project_id": 24,
+ "title": "v1.0-rc",
+ "description": "Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state": "closed",
+ "created_at": "2019-07-12T19:45:44.256Z",
+ "updated_at": "2019-07-12T19:45:44.256Z",
+ "due_date": "2019-08-16",
+ "start_date": "2019-07-30",
+ "web_url": "https://gitlab.example.com/root/awesome-app/-/milestones/1",
+ "issue_stats": {"total": 98, "closed": 76},
+ },
+ {
+ "id": 52,
+ "iid": 2,
+ "project_id": 24,
+ "title": "v1.0",
+ "description": "Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state": "closed",
+ "created_at": "2019-07-16T14:00:12.256Z",
+ "updated_at": "2019-07-16T14:00:12.256Z",
+ "due_date": "2019-08-16",
+ "start_date": "2019-07-30",
+ "web_url": "https://gitlab.example.com/root/awesome-app/-/milestones/2",
+ "issue_stats": {"total": 24, "closed": 21},
+ },
+ ],
+ "commit_path": "/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
+ "tag_path": "/root/awesome-app/-/tags/v0.11.1",
+ "assets": {
+ "count": 6,
+ "sources": [
+ {
+ "format": "zip",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.zip",
+ },
+ {
+ "format": "tar.gz",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.tar.gz",
+ },
+ {
+ "format": "tar.bz2",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.tar.bz2",
+ },
+ {
+ "format": "tar",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.2/awesome-app-v0.2.tar",
+ },
+ ],
+ "links": [
+ {
+ "id": 2,
+ "name": "awesome-v0.2.msi",
+ "url": "http://192.168.10.15:3000/msi",
+ "link_type": "other",
+ },
+ {
+ "id": 1,
+ "name": "awesome-v0.2.dmg",
+ "url": "http://192.168.10.15:3000",
+ "link_type": "other",
+ },
+ ],
+ "evidence_file_path": "https://gitlab.example.com/root/awesome-app/-/releases/v0.2/evidence.json",
+ },
+ "evidences": [
+ {
+ "sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
+ "filepath": "https://gitlab.example.com/root/awesome-app/-/releases/v0.2/evidence.json",
+ "collected_at": "2019-01-03T01:56:19.539Z",
+ }
+ ],
+ },
+ {
+ "tag_name": "v0.1",
+ "description": "## CHANGELOG\r\n\r\n-Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516",
+ "name": "Awesome app v0.1 alpha",
+ "created_at": "2019-01-03T01:55:18.203Z",
+ "released_at": "2019-01-03T01:55:18.203Z",
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "commit": {
+ "id": "f8d3d94cbd347e924aa7b715845e439d00e80ca4",
+ "short_id": "f8d3d94c",
+ "title": "Initial commit",
+ "created_at": "2019-01-03T01:53:28.000Z",
+ "parent_ids": [],
+ "message": "Initial commit",
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2019-01-03T01:53:28.000Z",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2019-01-03T01:53:28.000Z",
+ },
+ "assets": {
+ "count": 4,
+ "sources": [
+ {
+ "format": "zip",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.zip",
+ },
+ {
+ "format": "tar.gz",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.gz",
+ },
+ {
+ "format": "tar.bz2",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.bz2",
+ },
+ {
+ "format": "tar",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar",
+ },
+ ],
+ "links": [],
+ "evidence_file_path": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json",
+ },
+ "evidences": [
+ {
+ "sha": "c3ffedec13af470e760d6cdfb08790f71cf52c6cde4d",
+ "filepath": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json",
+ "collected_at": "2019-01-03T01:55:18.203Z",
+ }
+ ],
+ "_links": {
+ "closed_issues_url": "https://gitlab.example.com/root/awesome-app/-/issues?release_tag=v0.1&scope=all&state=closed",
+ "closed_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=closed",
+ "edit_url": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/edit",
+ "merged_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=merged",
+ "opened_issues_url": "https://gitlab.example.com/root/awesome-app/-/issues?release_tag=v0.1&scope=all&state=opened",
+ "opened_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=opened",
+ "self": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1",
+ },
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Releases"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_release_response_2():
+ # Get a Release by a tag name
+ example_data = {
+ "tag_name": "v0.1",
+ "description": "## CHANGELOG\r\n\r\n- Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516",
+ "name": "Awesome app v0.1 alpha",
+ "created_at": "2019-01-03T01:55:18.203Z",
+ "released_at": "2019-01-03T01:55:18.203Z",
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "commit": {
+ "id": "f8d3d94cbd347e924aa7b715845e439d00e80ca4",
+ "short_id": "f8d3d94c",
+ "title": "Initial commit",
+ "created_at": "2019-01-03T01:53:28.000Z",
+ "parent_ids": [],
+ "message": "Initial commit",
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2019-01-03T01:53:28.000Z",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2019-01-03T01:53:28.000Z",
+ },
+ "milestones": [
+ {
+ "id": 51,
+ "iid": 1,
+ "project_id": 24,
+ "title": "v1.0-rc",
+ "description": "Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state": "closed",
+ "created_at": "2019-07-12T19:45:44.256Z",
+ "updated_at": "2019-07-12T19:45:44.256Z",
+ "due_date": "2019-08-16",
+ "start_date": "2019-07-30",
+ "web_url": "https://gitlab.example.com/root/awesome-app/-/milestones/1",
+ "issue_stats": {"total": 98, "closed": 76},
+ },
+ {
+ "id": 52,
+ "iid": 2,
+ "project_id": 24,
+ "title": "v1.0",
+ "description": "Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state": "closed",
+ "created_at": "2019-07-16T14:00:12.256Z",
+ "updated_at": "2019-07-16T14:00:12.256Z",
+ "due_date": "2019-08-16",
+ "start_date": "2019-07-30",
+ "web_url": "https://gitlab.example.com/root/awesome-app/-/milestones/2",
+ "issue_stats": {"total": 24, "closed": 21},
+ },
+ ],
+ "commit_path": "/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
+ "tag_path": "/root/awesome-app/-/tags/v0.11.1",
+ "assets": {
+ "count": 5,
+ "sources": [
+ {
+ "format": "zip",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.zip",
+ },
+ {
+ "format": "tar.gz",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.gz",
+ },
+ {
+ "format": "tar.bz2",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.bz2",
+ },
+ {
+ "format": "tar",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar",
+ },
+ ],
+ "links": [
+ {
+ "id": 3,
+ "name": "hoge",
+ "url": "https://gitlab.example.com/root/awesome-app/-/tags/v0.11.1/binaries/linux-amd64",
+ "link_type": "other",
+ }
+ ],
+ },
+ "evidences": [
+ {
+ "sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
+ "filepath": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json",
+ "collected_at": "2019-07-16T14:00:12.256Z",
+ },
+ ],
+ "_links": {
+ "closed_issues_url": "https://gitlab.example.com/root/awesome-app/-/issues?release_tag=v0.1&scope=all&state=closed",
+ "closed_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=closed",
+ "edit_url": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/edit",
+ "merged_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=merged",
+ "opened_issues_url": "https://gitlab.example.com/root/awesome-app/-/issues?release_tag=v0.1&scope=all&state=opened",
+ "opened_merge_requests_url": "https://gitlab.example.com/root/awesome-app/-/merge_requests?release_tag=v0.1&scope=all&state=opened",
+ "self": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Release"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_release_response_3():
+ # Create a release
+ example_data = {
+ "tag_name": "v0.3",
+ "description": "Super nice release",
+ "name": "New release",
+ "created_at": "2019-01-03T02:22:45.118Z",
+ "released_at": "2019-01-03T02:22:45.118Z",
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "commit": {
+ "id": "079e90101242458910cccd35eab0e211dfc359c0",
+ "short_id": "079e9010",
+ "title": "Update README.md",
+ "created_at": "2019-01-03T01:55:38.000Z",
+ "parent_ids": ["f8d3d94cbd347e924aa7b715845e439d00e80ca4"],
+ "message": "Update README.md",
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2019-01-03T01:55:38.000Z",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2019-01-03T01:55:38.000Z",
+ },
+ "milestones": [
+ {
+ "id": 51,
+ "iid": 1,
+ "project_id": 24,
+ "title": "v1.0-rc",
+ "description": "Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state": "closed",
+ "created_at": "2019-07-12T19:45:44.256Z",
+ "updated_at": "2019-07-12T19:45:44.256Z",
+ "due_date": "2019-08-16",
+ "start_date": "2019-07-30",
+ "web_url": "https://gitlab.example.com/root/awesome-app/-/milestones/1",
+ "issue_stats": {"total": 99, "closed": 76},
+ },
+ {
+ "id": 52,
+ "iid": 2,
+ "project_id": 24,
+ "title": "v1.0",
+ "description": "Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state": "closed",
+ "created_at": "2019-07-16T14:00:12.256Z",
+ "updated_at": "2019-07-16T14:00:12.256Z",
+ "due_date": "2019-08-16",
+ "start_date": "2019-07-30",
+ "web_url": "https://gitlab.example.com/root/awesome-app/-/milestones/2",
+ "issue_stats": {"total": 24, "closed": 21},
+ },
+ ],
+ "commit_path": "/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
+ "tag_path": "/root/awesome-app/-/tags/v0.11.1",
+ "evidence_sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
+ "assets": {
+ "count": 5,
+ "sources": [
+ {
+ "format": "zip",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.3/awesome-app-v0.3.zip",
+ },
+ {
+ "format": "tar.gz",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.3/awesome-app-v0.3.tar.gz",
+ },
+ {
+ "format": "tar.bz2",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.3/awesome-app-v0.3.tar.bz2",
+ },
+ {
+ "format": "tar",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.3/awesome-app-v0.3.tar",
+ },
+ ],
+ "links": [
+ {
+ "id": 3,
+ "name": "hoge",
+ "url": "https://gitlab.example.com/root/awesome-app/-/tags/v0.11.1/binaries/linux-amd64",
+ "link_type": "other",
+ }
+ ],
+ "evidence_file_path": "https://gitlab.example.com/root/awesome-app/-/releases/v0.3/evidence.json",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Release"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_release_response_4():
+ # Update a release
+ example_data = {
+ "tag_name": "v0.1",
+ "description": "## CHANGELOG\r\n\r\n- Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516",
+ "name": "new name",
+ "created_at": "2019-01-03T01:55:18.203Z",
+ "released_at": "2019-01-03T01:55:18.203Z",
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "commit": {
+ "id": "f8d3d94cbd347e924aa7b715845e439d00e80ca4",
+ "short_id": "f8d3d94c",
+ "title": "Initial commit",
+ "created_at": "2019-01-03T01:53:28.000Z",
+ "parent_ids": [],
+ "message": "Initial commit",
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2019-01-03T01:53:28.000Z",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2019-01-03T01:53:28.000Z",
+ },
+ "milestones": [
+ {
+ "id": 53,
+ "iid": 3,
+ "project_id": 24,
+ "title": "v1.2",
+ "description": "Voluptate fugiat possimus quis quod aliquam expedita.",
+ "state": "active",
+ "created_at": "2019-09-01T13:00:00.256Z",
+ "updated_at": "2019-09-01T13:00:00.256Z",
+ "due_date": "2019-09-20",
+ "start_date": "2019-09-05",
+ "web_url": "https://gitlab.example.com/root/awesome-app/-/milestones/3",
+ "issue_stats": {"opened": 11, "closed": 78},
+ }
+ ],
+ "commit_path": "/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
+ "tag_path": "/root/awesome-app/-/tags/v0.11.1",
+ "evidence_sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
+ "assets": {
+ "count": 4,
+ "sources": [
+ {
+ "format": "zip",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.zip",
+ },
+ {
+ "format": "tar.gz",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.gz",
+ },
+ {
+ "format": "tar.bz2",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.bz2",
+ },
+ {
+ "format": "tar",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar",
+ },
+ ],
+ "links": [],
+ "evidence_file_path": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Release"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_release_response_5():
+ # Delete a Release
+ example_data = {
+ "tag_name": "v0.1",
+ "description": "## CHANGELOG\r\n\r\n- Remove limit of 100 when searching repository code. !8671\r\n- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)\r\n- Fix a bug where internal email pattern wasn't respected. !22516",
+ "name": "new name",
+ "created_at": "2019-01-03T01:55:18.203Z",
+ "released_at": "2019-01-03T01:55:18.203Z",
+ "author": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
+ "web_url": "https://gitlab.example.com/root",
+ },
+ "commit": {
+ "id": "f8d3d94cbd347e924aa7b715845e439d00e80ca4",
+ "short_id": "f8d3d94c",
+ "title": "Initial commit",
+ "created_at": "2019-01-03T01:53:28.000Z",
+ "parent_ids": [],
+ "message": "Initial commit",
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2019-01-03T01:53:28.000Z",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2019-01-03T01:53:28.000Z",
+ },
+ "commit_path": "/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
+ "tag_path": "/root/awesome-app/-/tags/v0.11.1",
+ "evidence_sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
+ "assets": {
+ "count": 4,
+ "sources": [
+ {
+ "format": "zip",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.zip",
+ },
+ {
+ "format": "tar.gz",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.gz",
+ },
+ {
+ "format": "tar.bz2",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar.bz2",
+ },
+ {
+ "format": "tar",
+ "url": "https://gitlab.example.com/root/awesome-app/-/archive/v0.1/awesome-app-v0.1.tar",
+ },
+ ],
+ "links": [],
+ "evidence_file_path": "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Release"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_1():
+ # List owned runners
+ example_data = [
+ {
+ "active": True,
+ "paused": False,
+ "description": "test-1-20150125",
+ "id": 6,
+ "ip_address": "",
+ "is_shared": False,
+ "runner_type": "project_type",
+ "name": None,
+ "online": True,
+ "status": "online",
+ },
+ {
+ "active": True,
+ "paused": False,
+ "description": "test-2-20150125",
+ "id": 8,
+ "ip_address": "",
+ "is_shared": False,
+ "runner_type": "group_type",
+ "name": None,
+ "online": False,
+ "status": "offline",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Runners"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_2():
+ # List all runners
+ example_data = [
+ {
+ "active": True,
+ "paused": False,
+ "description": "shared-runner-1",
+ "id": 1,
+ "ip_address": "",
+ "is_shared": True,
+ "runner_type": "instance_type",
+ "name": None,
+ "online": True,
+ "status": "online",
+ },
+ {
+ "active": True,
+ "paused": False,
+ "description": "shared-runner-2",
+ "id": 3,
+ "ip_address": "",
+ "is_shared": True,
+ "runner_type": "instance_type",
+ "name": None,
+ "online": False,
+ "status": "offline",
+ },
+ {
+ "active": True,
+ "paused": False,
+ "description": "test-1-20150125",
+ "id": 6,
+ "ip_address": "",
+ "is_shared": False,
+ "runner_type": "project_type",
+ "name": None,
+ "online": True,
+ "status": "paused",
+ },
+ {
+ "active": True,
+ "paused": False,
+ "description": "test-2-20150125",
+ "id": 8,
+ "ip_address": "",
+ "is_shared": False,
+ "runner_type": "group_type",
+ "name": None,
+ "online": False,
+ "status": "offline",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Runners"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_3():
+ # Get runner details
+ example_data = {
+ "active": True,
+ "paused": False,
+ "architecture": None,
+ "description": "test-1-20150125",
+ "id": 6,
+ "ip_address": "",
+ "is_shared": False,
+ "runner_type": "project_type",
+ "contacted_at": "2016-01-25T16:39:48.066Z",
+ "maintenance_note": None,
+ "name": None,
+ "online": True,
+ "status": "online",
+ "platform": None,
+ "projects": [
+ {
+ "id": 1,
+ "name": "GitLab Community Edition",
+ "name_with_namespace": "GitLab.org / GitLab Community Edition",
+ "path": "gitlab-foss",
+ "path_with_namespace": "gitlab-org/gitlab-foss",
+ }
+ ],
+ "revision": None,
+ "tag_list": ["ruby", "mysql"],
+ "version": None,
+ "access_level": "ref_protected",
+ "maximum_timeout": 3600,
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Runner"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_4():
+ # List jobs processed by a runner
+ example_data = [
+ {
+ "id": 2,
+ "status": "running",
+ "stage": "test",
+ "name": "test",
+ "ref": "main",
+ "tag": False,
+ "coverage": None,
+ "created_at": "2017-11-16T08:50:29.000Z",
+ "started_at": "2017-11-16T08:51:29.000Z",
+ "finished_at": "2017-11-16T08:53:29.000Z",
+ "duration": 120,
+ "queued_duration": 2,
+ "user": {
+ "id": 1,
+ "name": "John Doe2",
+ "username": "user2",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
+ "web_url": "http://localhost/user2",
+ "created_at": "2017-11-16T18:38:46.000Z",
+ "bio": None,
+ "location": None,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": None,
+ },
+ "commit": {
+ "id": "97de212e80737a608d939f648d959671fb0a0142",
+ "short_id": "97de212e",
+ "title": "Update configuration\r",
+ "created_at": "2017-11-16T08:50:28.000Z",
+ "parent_ids": [
+ "1b12f15a11fc6e62177bef08f47bc7b5ce50b141",
+ "498214de67004b1da3d820901307bed2a68a8ef6",
+ ],
+ "message": "See merge request !123",
+ "author_name": "John Doe2",
+ "author_email": "user2@example.org",
+ "authored_date": "2017-11-16T08:50:27.000Z",
+ "committer_name": "John Doe2",
+ "committer_email": "user2@example.org",
+ "committed_date": "2017-11-16T08:50:27.000Z",
+ },
+ "pipeline": {
+ "id": 2,
+ "sha": "97de212e80737a608d939f648d959671fb0a0142",
+ "ref": "main",
+ "status": "running",
+ },
+ "project": {
+ "id": 1,
+ "description": None,
+ "name": "project1",
+ "name_with_namespace": "John Doe2 / project1",
+ "path": "project1",
+ "path_with_namespace": "namespace1/project1",
+ "created_at": "2017-11-16T18:38:46.620Z",
+ },
+ }
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Jobs"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_5():
+ # List project’s runners
+ example_data = [
+ {
+ "active": True,
+ "paused": False,
+ "description": "test-2-20150125",
+ "id": 8,
+ "ip_address": "",
+ "is_shared": False,
+ "runner_type": "project_type",
+ "name": None,
+ "online": False,
+ "status": "offline",
+ },
+ {
+ "active": True,
+ "paused": False,
+ "description": "development_runner",
+ "id": 5,
+ "ip_address": "",
+ "is_shared": True,
+ "runner_type": "instance_type",
+ "name": None,
+ "online": True,
+ "status": "online",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Runners"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_6():
+ # Enable runner for project
+ example_data = {
+ "active": True,
+ "description": "test-2016-02-01",
+ "id": 9,
+ "ip_address": "",
+ "is_shared": False,
+ "runner_type": "project_type",
+ "name": None,
+ "online": True,
+ "status": "online",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Runner"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_7():
+ # Create an instance runner
+ example_data = {
+ "id": 12345,
+ "token": "6337ff461c94fd3fa32ba3b1ff4125",
+ "token_expires_at": "2021-09-27T21:05:03.203Z",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Token"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_8():
+ # Verify authentication for a registered runner
+ example_data = {
+ "id": 12345,
+ "token": "glrt-6337ff461c94fd3fa32ba3b1ff4125",
+ "token_expires_at": "2021-09-27T21:05:03.203Z",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Token"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_9():
+ # Reset runner’s authentication token by using the runner ID
+ example_data = {
+ "token": "6337ff461c94fd3fa32ba3b1ff4125",
+ "token_expires_at": "2021-09-27T21:05:03.203Z",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Token"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_runner_response_10():
+ # Reset runner’s authentication token by using the current token
+ example_data = {
+ "token": "6337ff461c94fd3fa32ba3b1ff4125",
+ "token_expires_at": "2021-09-27T21:05:03.203Z",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "Token"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_wiki_response_1():
+ # List wiki pages
+ example_data = [
+ {
+ "content": "Here is an instruction how to deploy this project.",
+ "format": "markdown",
+ "slug": "deploy",
+ "title": "deploy",
+ "encoding": "UTF-8",
+ },
+ {
+ "content": "Our development process is described here.",
+ "format": "markdown",
+ "slug": "development",
+ "title": "development",
+ "encoding": "UTF-8",
+ },
+ {
+ "content": "* [Deploy](deploy)\n* [Development](development)",
+ "format": "markdown",
+ "slug": "home",
+ "title": "home",
+ "encoding": "UTF-8",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "WikiPages"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_wiki_response_2():
+ # Get a wiki page
+ example_data = {
+ "content": "home page",
+ "format": "markdown",
+ "slug": "home",
+ "title": "home",
+ "encoding": "UTF-8",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "WikiPage"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_wiki_response_3():
+ # Create a new wiki page
+ example_data = {
+ "content": "Hello world",
+ "format": "markdown",
+ "slug": "Hello",
+ "title": "Hello",
+ "encoding": "UTF-8",
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "WikiPage"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_wiki_response_4():
+ # Upload an attachment to the wiki repository
+ example_data = {
+ "file_name": "dk.png",
+ "file_path": "uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png",
+ "branch": "main",
+ "link": {
+ "url": "uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png",
+ "markdown": "![dk](uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png)",
+ },
+ }
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "WikiAttachment"
+
+
+@pytest.mark.skipif(
+ sys.platform in ["darwin"] or skip,
+ reason=reason,
+)
+def test_wiki_response_5():
+ # List wiki pages
+ example_data = [
+ {
+ "content": "Here is an instruction how to deploy this project.",
+ "format": "markdown",
+ "slug": "deploy",
+ "title": "deploy",
+ "encoding": "UTF-8",
+ },
+ {
+ "content": "Our development process is described here.",
+ "format": "markdown",
+ "slug": "development",
+ "title": "development",
+ "encoding": "UTF-8",
+ },
+ {
+ "content": "* [Deploy](deploy)\n* [Development](development)",
+ "format": "markdown",
+ "slug": "home",
+ "title": "home",
+ "encoding": "UTF-8",
+ },
+ ]
+ response = Response(data=example_data, status_code=200, json_output=example_data)
+ assert response.data.base_type == "WikiPages"
+
+
if __name__ == "__main__":
test_branch_model()
test_commit_model()
@@ -207,3 +9296,164 @@ def test_wiki_model():
test_runner_model()
test_user_model()
test_wiki_model()
+ test_project_response_1()
+ test_project_response_2()
+ test_user_response_1()
+ test_user_response_2()
+ test_branch_response_1()
+ test_branch_response_2()
+ test_branch_response_3()
+ test_branch_response_4()
+ test_commit_response_1()
+ test_commit_response_2()
+ test_commit_response_3()
+ test_commit_response_4()
+ test_commit_response_5()
+ test_commit_response_6()
+ test_commit_response_7()
+ test_commit_response_8()
+ test_commit_response_9()
+ test_commit_response_10()
+ test_commit_response_11()
+ test_commit_response_12()
+ test_commit_response_13()
+ test_commit_response_14()
+ test_commit_response_15()
+ test_commit_response_16()
+ test_commit_response_17()
+ test_commit_response_18()
+ test_commit_response_19()
+ test_deploy_token_response_1()
+ test_deploy_token_response_2()
+ test_deploy_token_response_3()
+ test_deploy_token_response_4()
+ test_deploy_token_response_5()
+ test_merge_request_response_1()
+ test_merge_request_response_2()
+ test_merge_request_response_3()
+ test_merge_request_response_4()
+ test_merge_request_response_5()
+ test_merge_request_response_6()
+ test_merge_request_response_7()
+ test_merge_request_response_8()
+ test_merge_request_response_9()
+ test_merge_request_response_10()
+ test_merge_request_response_11()
+ test_merge_request_response_12()
+ test_merge_request_response_13()
+ test_merge_request_response_14()
+ test_merge_request_response_15()
+ test_merge_request_response_16()
+ test_merge_request_response_17()
+ test_merge_request_response_18()
+ test_merge_request_response_19()
+ test_merge_request_response_20()
+ test_merge_request_response_21()
+ test_issues_response_1()
+ test_issues_response_2()
+ test_issues_response_3()
+ test_issues_response_4()
+ test_issues_response_5()
+ test_issues_response_6()
+ test_issues_response_7()
+ test_issues_response_8()
+ test_issues_response_9()
+ test_issues_response_10()
+ test_issues_response_11()
+ test_issues_response_12()
+ test_issues_response_13()
+ test_issues_response_14()
+ test_issues_response_15()
+ test_group_response_1()
+ test_group_response_2()
+ test_group_response_3()
+ test_group_response_4()
+ test_group_response_5()
+ test_group_response_6()
+ test_group_response_7()
+ test_group_response_8()
+ test_group_response_9()
+ test_group_response_10()
+ test_group_response_11()
+ test_group_response_12()
+ test_group_response_13()
+ test_group_response_14()
+ test_group_response_15()
+ test_group_response_16()
+ test_group_response_17()
+ test_group_response_18()
+ test_group_response_19()
+ test_group_response_20()
+ test_group_response_21()
+ test_jobs_response_1()
+ test_jobs_response_2()
+ test_jobs_response_3()
+ test_jobs_response_4()
+ test_jobs_response_5()
+ test_jobs_response_6()
+ test_jobs_response_7()
+ test_jobs_response_8()
+ test_jobs_response_9()
+ test_member_response_1()
+ test_member_response_2()
+ test_member_response_3()
+ test_member_response_4()
+ test_member_response_5()
+ test_member_response_6()
+ test_member_response_7()
+ test_member_response_8()
+ test_approval_rule_response_1()
+ test_approval_rule_response_2()
+ test_approval_rule_response_3()
+ test_approval_rule_response_4()
+ test_approval_rule_response_5()
+ test_approval_rule_response_6()
+ test_approval_rule_response_7()
+ test_approval_rule_response_8()
+ test_approval_rule_response_9()
+ test_approval_rule_response_10()
+ test_approval_rule_response_11()
+ test_approval_rule_response_12()
+ test_approval_rule_response_13()
+ test_approval_rule_response_14()
+ test_approval_rule_response_15()
+ test_protected_branch_response_1()
+ test_protected_branch_response_2()
+ test_protected_branch_response_3()
+ test_protected_branch_response_4()
+ test_protected_branch_response_5()
+ test_protected_branch_response_6()
+ test_protected_branch_response_7()
+ test_protected_branch_response_8()
+ test_protected_branch_response_9()
+ test_protected_branch_response_10()
+ test_protected_branch_response_11()
+ test_protected_branch_response_12()
+ test_protected_branch_response_13()
+ test_protected_branch_response_14()
+ test_protected_branch_response_15()
+ test_package_response_1()
+ test_package_response_2()
+ test_package_response_3()
+ test_package_response_4()
+ test_package_response_5()
+ test_release_response_1()
+ test_release_response_2()
+ test_release_response_3()
+ test_release_response_4()
+ test_release_response_5()
+ test_runner_response_1()
+ test_runner_response_2()
+ test_runner_response_3()
+ test_runner_response_4()
+ test_runner_response_5()
+ test_runner_response_6()
+ test_runner_response_7()
+ test_runner_response_8()
+ test_runner_response_9()
+ test_runner_response_10()
+ test_wiki_response_1()
+ test_wiki_response_2()
+ test_wiki_response_3()
+ test_wiki_response_4()
+ test_wiki_response_5()