def test_regression_error_before_update( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, review: PRReview, check_run: CheckRun, ) -> None: branch_protection.requiresStatusChecks = True branch_protection.requiredStatusCheckContexts = ["ci/backend", "wip-app"] branch_protection.requiresStrictStatusChecks = True pull_request.mergeStateStatus = MergeStateStatus.BEHIND contexts = [StatusContext(context="ci/backend", state=StatusState.SUCCESS)] check_run.name = "wip-app" check_run.conclusion = CheckConclusionState.SUCCESS with pytest.raises(NeedsBranchUpdate): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=1, reviews=[review], check_runs=[check_run], contexts=contexts, valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_failing_checks( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, review: PRReview, context: StatusContext, check_run: CheckRun, ) -> None: pull_request.mergeStateStatus = MergeStateStatus.BLOCKED branch_protection.requiredStatusCheckContexts = ["ci/backend", "wip-app"] context.context = "ci/backend" context.state = StatusState.SUCCESS check_run.name = "wip-app" check_run.conclusion = CheckConclusionState.FAILURE with pytest.raises(NotQueueable, match="failing required status checks"): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[review], contexts=[context], check_runs=[check_run], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_dont_update_before_block( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, review: PRReview, context: StatusContext, ) -> None: """ Regression test for when Kodiak would update a PR that is not mergeable. We were raising the NeedsBranchUpdate exception too early. """ pull_request.mergeStateStatus = MergeStateStatus.BEHIND branch_protection.requiresStrictStatusChecks = True with pytest.raises(NeedsBranchUpdate): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[review], contexts=[context], check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_regression_mishandling_multiple_reviews_okay_reviews( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, check_run: CheckRun, context: StatusContext, ) -> None: pull_request.mergeStateStatus = MergeStateStatus.BEHIND branch_protection.requiresApprovingReviews = True branch_protection.requiredApprovingReviewCount = 1 first_review_date = datetime(2010, 5, 15) latest_review_date = first_review_date + timedelta(minutes=20) reviews = [ PRReview( state=PRReviewState.CHANGES_REQUESTED, createdAt=first_review_date, author=PRReviewAuthor(login="******"), authorAssociation=CommentAuthorAssociation.CONTRIBUTOR, ), PRReview( state=PRReviewState.COMMENTED, createdAt=latest_review_date, author=PRReviewAuthor(login="******"), authorAssociation=CommentAuthorAssociation.CONTRIBUTOR, ), PRReview( state=PRReviewState.APPROVED, createdAt=latest_review_date, author=PRReviewAuthor(login="******"), authorAssociation=CommentAuthorAssociation.CONTRIBUTOR, ), PRReview( state=PRReviewState.APPROVED, createdAt=latest_review_date, author=PRReviewAuthor(login="******"), authorAssociation=CommentAuthorAssociation.CONTRIBUTOR, ), ] with pytest.raises(NeedsBranchUpdate): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=1, reviews=reviews, check_runs=[check_run], contexts=[context], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_config_merge_optimistic_updates( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule ) -> None: """ If optimisitc_updates are enabled, branch updates should be prioritized over waiting for running status checks to complete. Otherwise, status checks should be checked before updating. """ branch_protection.requiredApprovingReviewCount = 0 branch_protection.requiresStrictStatusChecks = True pull_request.mergeStateStatus = MergeStateStatus.BEHIND branch_protection.requiresStatusChecks = True branch_protection.requiredStatusCheckContexts = ["ci/lint", "ci/test"] contexts: List[StatusContext] = [] config.merge.optimistic_updates = True with pytest.raises(NeedsBranchUpdate): mergeable( app_id="1234", config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[], contexts=contexts, check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], ) config.merge.optimistic_updates = False with pytest.raises(WaitingForChecks): mergeable( app_id="1234", config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[], contexts=contexts, check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_unknown_blockage( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule ) -> None: branch_protection.requiredApprovingReviewCount = 0 branch_protection.requiresStatusChecks = False pull_request.mergeStateStatus = MergeStateStatus.BLOCKED with pytest.raises(NotQueueable, match="determine why PR is blocked"): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[], contexts=[], check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_need_update( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, review: PRReview, context: StatusContext, ) -> None: with pytest.raises(NeedsBranchUpdate): pull_request.mergeStateStatus = MergeStateStatus.BEHIND mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[review], contexts=[context], check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_requires_signature( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, review: PRReview, context: StatusContext, ) -> None: pull_request.mergeStateStatus = MergeStateStatus.BLOCKED branch_protection.requiresCommitSignatures = True with pytest.raises(NotQueueable, match="missing required signature"): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[review], contexts=[context], check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_blocking_review( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, review: PRReview, context: StatusContext, ) -> None: pull_request.mergeStateStatus = MergeStateStatus.BLOCKED review.state = PRReviewState.CHANGES_REQUESTED with pytest.raises(NotQueueable, match="blocking review"): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[review], contexts=[context], check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_missing_required_context( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule, review: PRReview, context: StatusContext, ) -> None: pull_request.mergeStateStatus = MergeStateStatus.BLOCKED branch_protection.requiredStatusCheckContexts = ["ci/backend", "ci/frontend"] context.context = "ci/backend" with pytest.raises(WaitingForChecks, match="missing required status checks"): mergeable( config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[review], contexts=[context], check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )
def test_merge_state_status_draft( pull_request: PullRequest, config: V1, branch_protection: BranchProtectionRule ) -> None: """ If optimisitc_updates are enabled, branch updates should be prioritized over waiting for running status checks to complete. Otherwise, status checks should be checked before updating. """ pull_request.mergeStateStatus = MergeStateStatus.DRAFT with pytest.raises(NotQueueable, match="draft state"): mergeable( app_id="1234", config=config, pull_request=pull_request, branch_protection=branch_protection, review_requests_count=0, reviews=[], contexts=[], check_runs=[], valid_signature=False, valid_merge_methods=[MergeMethod.squash], )