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()