class TestSquashAndMergeJob:
    gas_client = GAS("Accesskey-********************************")
    dataset_client = DatasetClient(
        "test_dataset",
        "12345",
        gas_client,
        status=Status(DEFAULT_BRANCH, commit_id=ROOT_COMMIT_ID),
        alias="",
        is_public=True,
    )
    squash_and_merge_job1 = SquashAndMergeJob(
        client=dataset_client.squash_and_merge._client,
        dataset_id=dataset_client.dataset_id,
        job_updater=dataset_client.squash_and_merge._get_job,
        draft_getter=dataset_client.get_draft,
        title="test->main(abort)",
        job_id="234",
        arguments={"title": "draft-1"},
        created_at=1,
        started_at=None,
        finished_at=None,
        status="QUEUEING",
        error_message="",
        result=None,
        description="12",
    )
    squash_and_merge_job2 = SquashAndMergeJob(
        client=dataset_client.squash_and_merge._client,
        dataset_id=dataset_client.dataset_id,
        job_updater=dataset_client.squash_and_merge._get_job,
        draft_getter=dataset_client.get_draft,
        title="test->main(abort)",
        job_id="123",
        arguments={"title": "draft-1"},
        created_at=1,
        started_at=2,
        finished_at=3,
        status="SUCCESS",
        error_message="",
        result={"draftNumber": 1},
        description="12",
    )

    def test_result(self, mocker, mock_list_drafts):
        list_drafts, drafts_list = mock_list_drafts(mocker, "main")
        assert self.squash_and_merge_job1.result is None
        draft_numbers = (item.number for item in drafts_list)
        assert self.squash_and_merge_job2.result.number in draft_numbers
 def test__generate_jobs(self, mocker, mock_list_jobs):
     status, offset, limit = None, 0, 128
     params = {
         "jobType": "squashAndMerge",
         "status": status,
         "offset": offset,
         "limit": limit,
     }
     open_api_do, response_data = mock_list_jobs(mocker)
     job_generator = ReturnGenerator(
         self.dataset_client.squash_and_merge._generate_jobs())
     assert list(job_generator) == [
         SquashAndMergeJob.from_response_body(
             item,
             dataset_id=self.dataset_client.squash_and_merge._dataset_id,
             client=self.dataset_client.squash_and_merge._client,
             job_updater=self.dataset_client.squash_and_merge._get_job,
             draft_getter=self.dataset_client.squash_and_merge.
             _draft_getter,
         ) for item in response_data["jobs"]
     ]
     open_api_do.assert_called_once_with("GET",
                                         "jobs",
                                         self.dataset_client.dataset_id,
                                         params=params)
     assert job_generator.value == response_data["totalCount"]
 def test_create_job(self, mocker, mock_create_job):
     title, description = "", "12"
     source_branch_name = "branch-1"
     draft_title, draft_description = "draft-1", ""
     strategy = "abort"
     with pytest.raises(StatusError):
         self.dataset_client.squash_and_merge._status.branch_name = None
         self.dataset_client.squash_and_merge.create_job(
             title=title,
             description=description,
             draft_title=draft_title,
             source_branch_name=source_branch_name,
             target_branch_name=None,
             draft_description=draft_description,
             strategy=strategy,
         )
     self.dataset_client._status.checkout(commit_id="commit-1")
     self.dataset_client.squash_and_merge._status.branch_name = "branch-2"
     target_branch_name = "branch-2"
     title = f"{source_branch_name}->{target_branch_name}({strategy})"
     arguments = {
         "title": draft_title,
         "sourceBranchName": source_branch_name,
         "targetBranchName": target_branch_name,
         "strategy": strategy,
     }
     post_data = {
         "title": title,
         "jobType": "squashAndMerge",
         "arguments": arguments,
         "description": description,
     }
     open_api_do, job_info = mock_create_job(mocker)
     job_info.update(title=title,
                     arguments=arguments,
                     status="QUEUING",
                     description=description)
     assert self.dataset_client.squash_and_merge.create_job(
         title=title,
         description=description,
         draft_title=draft_title,
         source_branch_name=source_branch_name,
         target_branch_name=None,
         draft_description=draft_description,
         strategy=strategy,
     ) == SquashAndMergeJob.from_response_body(
         job_info,
         dataset_id=self.dataset_client.squash_and_merge._dataset_id,
         client=self.dataset_client.squash_and_merge._client,
         job_updater=self.dataset_client.squash_and_merge._get_job,
         draft_getter=self.dataset_client.squash_and_merge._draft_getter,
     )
     open_api_do.assert_called_once_with("POST",
                                         "jobs",
                                         self.dataset_client.dataset_id,
                                         json=post_data)
 def test_get_job(self, mocker, mock_get_job):
     job_id = "123"
     open_api_do, job_info = mock_get_job(mocker)
     assert self.dataset_client.squash_and_merge.get_job(
         job_id) == SquashAndMergeJob.from_response_body(
             job_info,
             dataset_id=self.dataset_client.squash_and_merge._dataset_id,
             client=self.dataset_client.squash_and_merge._client,
             job_updater=self.dataset_client.squash_and_merge._get_job,
             draft_getter=self.dataset_client.squash_and_merge.
             _draft_getter,
         )
     open_api_do.assert_called_once_with("GET", f"jobs/{job_id}",
                                         self.dataset_client.dataset_id)
    def _generate_jobs(
        self,
        status: Optional[str] = None,
        offset: int = 0,
        limit: int = 128,
    ) -> Generator[SquashAndMergeJob, None, int]:
        response = self._list_jobs(self._JOB_TYPE, status, offset, limit)
        for item in response["jobs"]:
            yield SquashAndMergeJob.from_response_body(
                item,
                dataset_id=self._dataset_id,
                client=self._client,
                job_updater=self._get_job,
                draft_getter=self._draft_getter,
            )

        return response["totalCount"]  # type: ignore[no-any-return]
    def get_job(self, job_id: str) -> SquashAndMergeJob:
        """Get a :class:`SquashAndMergeJob`.

        Arguments:
            job_id: The SquashAndMergeJob id.

        Returns:
            The SquashAndMergeJob.

        """
        job_info = self._get_job(job_id)
        return SquashAndMergeJob.from_response_body(
            job_info,
            dataset_id=self._dataset_id,
            client=self._client,
            job_updater=self._get_job,
            draft_getter=self._draft_getter,
        )
    def create_job(
        self,
        title: str = "",
        description: str = "",
        *,
        draft_title: str,
        source_branch_name: str,
        target_branch_name: Optional[str] = None,
        draft_description: str = "",
        strategy: Optional[str] = "abort",
    ) -> SquashAndMergeJob:
        """Create a :class:`SquashAndMergeJob`.

        Squash commits in source branch, then merge into target branch by creating a new draft.
        If the target branch name is not given, the draft will be based on the branch name stored
        in the dataset client. And during merging, the conflicts between branches can be resolved
        in three different strategies: "abort", "override" and "skip".

        Arguments:
            title: The SquashAndMergeJob title.
            description: The SquashAndMergeJob description.
            draft_title: The draft title.
            source_branch_name: The name of the branch to be squashed.
            target_branch_name: The target branch name of the merge operation.
            draft_description: The draft description.
            strategy: The strategy of handling the branch conflict. There are three options:

                1. "abort": abort the opetation;
                2. "override": the squashed branch will override the target branch;
                3. "skip": keep the origin branch.

        Raises:
            StatusError: When squashing and merging without basing on a branch.

        Returns:
            The SquashAndMergeJob.

        """
        if not target_branch_name:
            target_branch_name = self._status.branch_name
            if not target_branch_name:
                raise StatusError(
                    message="Squash and merge without basing on a branch is not allowed"
                )
            self._status.check_authority_for_commit()

        if not title:
            title = f"{source_branch_name}->{target_branch_name}({strategy})"

        arguments = {
            "title": draft_title,
            "sourceBranchName": source_branch_name,
            "targetBranchName": target_branch_name,
            "strategy": strategy,
        }
        if draft_description:
            arguments["description"] = draft_description

        job_info = self._create_job(title, self._JOB_TYPE, arguments, description)
        return SquashAndMergeJob.from_response_body(
            job_info,
            dataset_id=self._dataset_id,
            client=self._client,
            job_updater=self._get_job,
            draft_getter=self._draft_getter,
        )