diff --git a/plugins/github/resources/graphql/fragment/pullRequestInfo.graphql b/plugins/github/resources/graphql/fragment/pullRequestInfo.graphql index d9ef3a48580e..7dc4fab8a116 100644 --- a/plugins/github/resources/graphql/fragment/pullRequestInfo.graphql +++ b/plugins/github/resources/graphql/fragment/pullRequestInfo.graphql @@ -24,6 +24,12 @@ fragment pullRequestInfo on PullRequest { isFork } + baseRef { + refUpdateRule { + ...refUpdateRule + } + } + headRefName headRefOid headRepository { diff --git a/plugins/github/resources/graphql/fragment/refUpdateRule.graphql b/plugins/github/resources/graphql/fragment/refUpdateRule.graphql new file mode 100644 index 000000000000..7be31c0fabb7 --- /dev/null +++ b/plugins/github/resources/graphql/fragment/refUpdateRule.graphql @@ -0,0 +1,10 @@ +fragment refUpdateRule on RefUpdateRule { + allowsDeletions + allowsForcePushes + pattern + requiredApprovingReviewCount + requiredStatusCheckContexts + requiresLinearHistory + requiresSignatures + viewerCanPush +} \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GHEServerVersionChecker.kt b/plugins/github/src/org/jetbrains/plugins/github/api/GHEServerVersionChecker.kt index 0b80b173411e..dc3cfa3e2001 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GHEServerVersionChecker.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GHEServerVersionChecker.kt @@ -3,8 +3,8 @@ package org.jetbrains.plugins.github.api object GHEServerVersionChecker { - private const val REQUIRED_VERSION_MAJOR = 2 - private const val REQUIRED_VERSION_MINOR = 21 + private const val REQUIRED_VERSION_MAJOR = 3 + private const val REQUIRED_VERSION_MINOR = 0 const val ENTERPRISE_VERSION_HEADER = "x-github-enterprise-version" diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiRequests.kt b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiRequests.kt index b3a5d3340158..4077de61bb8f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiRequests.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiRequests.kt @@ -5,7 +5,6 @@ import com.intellij.util.ThrowableConvertor import org.jetbrains.plugins.github.api.GithubApiRequest.* import org.jetbrains.plugins.github.api.data.* import org.jetbrains.plugins.github.api.data.request.* -import org.jetbrains.plugins.github.api.util.GHSchemaPreview import org.jetbrains.plugins.github.api.util.GithubApiPagesLoader import org.jetbrains.plugins.github.api.util.GithubApiSearchQueryBuilder import org.jetbrains.plugins.github.api.util.GithubApiUrlQueryBuilder @@ -142,10 +141,6 @@ object GithubApiRequests { @JvmStatic fun get(url: String) = Get.jsonPage(url).withOperationName("get branches") - - @JvmStatic - fun getProtection(repository: GHRepositoryCoordinates, branchName: String): GithubApiRequest = - Get.json(getUrl(repository, urlSuffix, "/$branchName", "/protection"), GHSchemaPreview.BRANCH_PROTECTION.mimeType) } object Commits : Entity("/commits") { diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/data/GHBranchProtectionRules.kt b/plugins/github/src/org/jetbrains/plugins/github/api/data/GHBranchProtectionRules.kt deleted file mode 100644 index 2ce973264cad..000000000000 --- a/plugins/github/src/org/jetbrains/plugins/github/api/data/GHBranchProtectionRules.kt +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.plugins.github.api.data - -class GHBranchProtectionRules(val requiredStatusChecks: RequiredStatusChecks?, - val enforceAdmins: EnforceAdmins?, - val requiredPullRequestReviews: RequiredPullRequestReviews?, - val restrictions: Restrictions?) { - - class RequiredStatusChecks(val strict: Boolean, val contexts: List) - - class EnforceAdmins(val enabled: Boolean) - - class RequiredPullRequestReviews(val requiredApprovingReviewCount: Int) - - class Restrictions(val users: List?, val teams: List?) - - class UserLogin(val login: String) - - class TeamSlug(val slug: String) -} diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/data/GHRefUpdateRule.kt b/plugins/github/src/org/jetbrains/plugins/github/api/data/GHRefUpdateRule.kt new file mode 100644 index 000000000000..01047f354097 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/api/data/GHRefUpdateRule.kt @@ -0,0 +1,24 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.plugins.github.api.data + +import com.intellij.collaboration.api.dto.GraphQLFragment + +@GraphQLFragment("graphql/fragment/refUpdateRule.graphql") +data class GHRefUpdateRule( + //Can this branch be deleted. + val allowsDeletions: Boolean, + //Are force pushes allowed on this branch. + val allowsForcePushes: Boolean, + //Identifies the protection rule pattern. + val pattern: String, + //Number of approving reviews required to update matching branches. + val requiredApprovingReviewCount: Int?, + //List of required status check contexts that must pass for commits to be accepted to matching branches. + val requiredStatusCheckContexts: List, + //Are merge commits prohibited from being pushed to this branch. + val requiresLinearHistory: Boolean, + //Are commits required to be signed. + val requiresSignatures: Boolean, + //Can the viewer push to the branch + val viewerCanPush: Boolean +) \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/data/pullrequest/GHPullRequest.kt b/plugins/github/src/org/jetbrains/plugins/github/api/data/pullrequest/GHPullRequest.kt index c7c9b8c189ba..631ff1a975e6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/data/pullrequest/GHPullRequest.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/api/data/pullrequest/GHPullRequest.kt @@ -8,6 +8,7 @@ import com.intellij.collaboration.api.dto.GraphQLNodesDTO import com.intellij.openapi.util.NlsSafe import org.jetbrains.plugins.github.api.data.GHActor import org.jetbrains.plugins.github.api.data.GHLabel +import org.jetbrains.plugins.github.api.data.GHRefUpdateRule import org.jetbrains.plugins.github.api.data.GHUser import java.util.* @@ -33,6 +34,7 @@ class GHPullRequest(id: String, val baseRefName: String, val baseRefOid: String, val baseRepository: Repository?, + baseRef: BaseRef?, val headRefName: String, val headRefOid: String, val headRepository: HeadRepository?) @@ -42,6 +44,9 @@ class GHPullRequest(id: String, @JsonIgnore val reviews: List = reviews.nodes + @JsonIgnore + val baseRefUpdateRule: GHRefUpdateRule? = baseRef?.refUpdateRule + open class Repository(val owner: Owner, val isFork: Boolean) class HeadRepository(owner: Owner, isFork: Boolean, @@ -50,6 +55,8 @@ class GHPullRequest(id: String, val sshUrl: @NlsSafe String) : Repository(owner, isFork) + data class BaseRef(val refUpdateRule: GHRefUpdateRule?) + class Owner(val login: String) override fun equals(other: Any?): Boolean { diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt index d00b25758cb2..71407ad57622 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRDataContextRepository.kt @@ -22,7 +22,6 @@ import org.jetbrains.plugins.github.api.GHGQLRequests import org.jetbrains.plugins.github.api.GHRepositoryCoordinates import org.jetbrains.plugins.github.api.GithubApiRequestExecutor import org.jetbrains.plugins.github.api.GithubApiRequests -import org.jetbrains.plugins.github.api.data.GHRepositoryOwnerName import org.jetbrains.plugins.github.api.data.GHUser import org.jetbrains.plugins.github.api.util.SimpleGHGQLPagesLoader import org.jetbrains.plugins.github.authentication.accounts.GithubAccount @@ -102,25 +101,13 @@ internal class GHPRDataContextRepository(private val project: Project, parentCs: accountDetails.name) - val repoOwner = repositoryInfo.owner - val currentUserTeams = if (repoOwner is GHRepositoryOwnerName.Organization) { - suspendingApiCall { indicator -> - SimpleGHGQLPagesLoader(requestExecutor, { - GHGQLRequests.Organization.Team.findByUserLogins(account.server, repoOwner.login, listOf(currentUser.login), it) - }).loadAll(indicator) - } - } - else { - emptyList() - } - // repository might have been renamed/moved val apiRepositoryPath = repositoryInfo.path val apiRepositoryCoordinates = GHRepositoryCoordinates(account.server, apiRepositoryPath) val securityService = GHPRSecurityServiceImpl(GithubSharedProjectSettings.getInstance(project), ghostUserDetails, - account, currentUser, currentUserTeams, + account, currentUser, repositoryInfo) val detailsService = GHPRDetailsServiceImpl(ProgressManager.getInstance(), requestExecutor, apiRepositoryCoordinates) val stateService = GHPRStateServiceImpl(ProgressManager.getInstance(), project, securityService, @@ -150,7 +137,7 @@ internal class GHPRDataContextRepository(private val project: Project, parentCs: val repoDataService = GHPRRepositoryDataServiceImpl(ProgressManager.getInstance(), requestExecutor, remoteCoordinates, apiRepositoryCoordinates, - repoOwner, + repositoryInfo.owner, repositoryInfo.id, repositoryInfo.defaultBranch, repositoryInfo.isFork) val iconsScope = contextScope.childScope(Dispatchers.Main) diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRMergeabilityStateBuilder.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRMergeabilityStateBuilder.kt index f50b446e7688..bf10dd7f4429 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRMergeabilityStateBuilder.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/GHPRMergeabilityStateBuilder.kt @@ -3,16 +3,13 @@ package org.jetbrains.plugins.github.pullrequest.data import com.intellij.collaboration.ui.codereview.details.data.CodeReviewCIJob import com.intellij.collaboration.ui.codereview.details.data.CodeReviewCIJobState -import com.intellij.util.containers.nullize -import org.jetbrains.plugins.github.api.data.GHBranchProtectionRules import org.jetbrains.plugins.github.api.data.GHCommitCheckSuiteConclusion import org.jetbrains.plugins.github.api.data.GHCommitStatusContextState -import org.jetbrains.plugins.github.api.data.GHRepositoryPermissionLevel +import org.jetbrains.plugins.github.api.data.GHRefUpdateRule import org.jetbrains.plugins.github.api.data.pullrequest.GHPullRequestMergeStateStatus import org.jetbrains.plugins.github.api.data.pullrequest.GHPullRequestMergeabilityData import org.jetbrains.plugins.github.api.data.pullrequest.GHPullRequestMergeableState import org.jetbrains.plugins.github.pullrequest.data.GHPRMergeabilityState.ChecksState -import org.jetbrains.plugins.github.pullrequest.data.service.GHPRSecurityService class GHPRMergeabilityStateBuilder(private val headRefOid: String, private val prHtmlUrl: String, private val mergeabilityData: GHPullRequestMergeabilityData) { @@ -22,18 +19,12 @@ class GHPRMergeabilityStateBuilder(private val headRefOid: String, private val p private var isRestricted = false private var requiredApprovingReviewsCount = 0 - fun withRestrictions(securityService: GHPRSecurityService, baseBranchProtectionRules: GHBranchProtectionRules) { - canOverrideAsAdmin = baseBranchProtectionRules.enforceAdmins?.enabled == false && - securityService.currentUserHasPermissionLevel(GHRepositoryPermissionLevel.ADMIN) - requiredContexts = baseBranchProtectionRules.requiredStatusChecks?.contexts.orEmpty() - - val restrictions = baseBranchProtectionRules.restrictions - val allowedLogins = restrictions?.users?.map { it.login }.nullize() - val allowedTeams = restrictions?.teams?.map { it.slug }.nullize() - isRestricted = (allowedLogins != null && !allowedLogins.contains(securityService.currentUser.login)) || - (allowedTeams != null && !securityService.isUserInAnyTeam(allowedTeams)) - - requiredApprovingReviewsCount = baseBranchProtectionRules.requiredPullRequestReviews?.requiredApprovingReviewCount ?: 0 + fun withRestrictions(currentUserIsAdmin: Boolean, refUpdateRule: GHRefUpdateRule) { + // TODO: load via PullRequest.viewerCanMergeAsAdmin when we update the min version + canOverrideAsAdmin = /*baseBranchProtectionRules.enforceAdmins?.enabled == false &&*/currentUserIsAdmin + requiredContexts = refUpdateRule.requiredStatusCheckContexts.filterNotNull() + isRestricted = !refUpdateRule.viewerCanPush + requiredApprovingReviewsCount = refUpdateRule.requiredApprovingReviewCount ?: 0 } fun build(): GHPRMergeabilityState { diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/provider/GHPRStateDataProviderImpl.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/provider/GHPRStateDataProviderImpl.kt index cd1f0f9c6e3b..a28be4348fc5 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/provider/GHPRStateDataProviderImpl.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/provider/GHPRStateDataProviderImpl.kt @@ -35,7 +35,6 @@ class GHPRStateDataProviderImpl(private val stateService: GHPRStateService, val details = detailsData.loadedDetails ?: return@addDetailsLoadedListener if (lastKnownBaseBranch != null && lastKnownBaseBranch != details.baseRefName) { - baseBranchProtectionRulesRequestValue.drop() reloadMergeabilityState() } lastKnownBaseBranch = details.baseRefName @@ -50,18 +49,9 @@ class GHPRStateDataProviderImpl(private val stateService: GHPRStateService, } } - private val baseBranchProtectionRulesRequestValue = LazyCancellableBackgroundProcessValue.create { indicator -> - detailsData.loadDetails().thenCompose { - stateService.loadBranchProtectionRules(indicator, pullRequestId, it.baseRefName) - } - } private val mergeabilityStateRequestValue = LazyCancellableBackgroundProcessValue.create { indicator -> - val baseBranchProtectionRulesRequest = baseBranchProtectionRulesRequestValue.value detailsData.loadDetails().thenCompose { details -> - - baseBranchProtectionRulesRequest.thenCompose { - stateService.loadMergeabilityState(indicator, pullRequestId, details.headRefOid, details.url, it) - } + stateService.loadMergeabilityState(indicator, pullRequestId, details.headRefOid, details.url, details.baseRefUpdateRule) } } @@ -89,8 +79,6 @@ class GHPRStateDataProviderImpl(private val stateService: GHPRStateService, } override fun reloadMergeabilityState() { - if (baseBranchProtectionRulesRequestValue.lastLoadedValue == null) - baseBranchProtectionRulesRequestValue.drop() mergeabilityStateRequestValue.drop() } @@ -122,6 +110,5 @@ class GHPRStateDataProviderImpl(private val stateService: GHPRStateService, override fun dispose() { mergeabilityStateRequestValue.drop() - baseBranchProtectionRulesRequestValue.drop() } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityService.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityService.kt index 097386173c4e..a934c25c68e8 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityService.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityService.kt @@ -20,5 +20,4 @@ interface GHPRSecurityService { fun isSquashMergeAllowed(): Boolean fun isMergeForbiddenForProject(): Boolean - fun isUserInAnyTeam(slugs: List): Boolean } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityServiceImpl.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityServiceImpl.kt index a34c3f9e761f..8eeb30901f0b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityServiceImpl.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRSecurityServiceImpl.kt @@ -5,7 +5,6 @@ import org.jetbrains.plugins.github.api.data.GHRepository import org.jetbrains.plugins.github.api.data.GHRepositoryPermissionLevel import org.jetbrains.plugins.github.api.data.GHUser import org.jetbrains.plugins.github.api.data.GithubUser -import org.jetbrains.plugins.github.api.data.pullrequest.GHTeam import org.jetbrains.plugins.github.authentication.accounts.GithubAccount import org.jetbrains.plugins.github.util.GithubSharedProjectSettings @@ -13,15 +12,12 @@ class GHPRSecurityServiceImpl(private val sharedProjectSettings: GithubSharedPro override val ghostUser: GHUser, override val account: GithubAccount, override val currentUser: GHUser, - private val currentUserTeams: List, private val repo: GHRepository) : GHPRSecurityService { override fun isCurrentUser(user: GithubUser) = user.nodeId == currentUser.id override fun currentUserHasPermissionLevel(level: GHRepositoryPermissionLevel) = (repo.viewerPermission?.ordinal ?: -1) >= level.ordinal - override fun isUserInAnyTeam(slugs: List) = currentUserTeams.any { slugs.contains(it.slug) } - override fun isMergeAllowed() = repo.mergeCommitAllowed override fun isRebaseMergeAllowed() = repo.rebaseMergeAllowed override fun isSquashMergeAllowed() = repo.squashMergeAllowed diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateService.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateService.kt index af8981b705ec..76b7a6b2dae9 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateService.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateService.kt @@ -3,23 +3,19 @@ package org.jetbrains.plugins.github.pullrequest.data.service import com.intellij.openapi.progress.ProgressIndicator import org.jetbrains.annotations.CalledInAny -import org.jetbrains.plugins.github.api.data.GHBranchProtectionRules +import org.jetbrains.plugins.github.api.data.GHRefUpdateRule import org.jetbrains.plugins.github.pullrequest.data.GHPRIdentifier import org.jetbrains.plugins.github.pullrequest.data.GHPRMergeabilityState import java.util.concurrent.CompletableFuture interface GHPRStateService { - @CalledInAny - fun loadBranchProtectionRules(progressIndicator: ProgressIndicator, pullRequestId: GHPRIdentifier, baseBranch: String) - : CompletableFuture - @CalledInAny fun loadMergeabilityState(progressIndicator: ProgressIndicator, pullRequestId: GHPRIdentifier, headRefOid: String, prHtmlUrl: String, - baseBranchProtectionRules: GHBranchProtectionRules?): CompletableFuture + baseRefUpdateRule: GHRefUpdateRule?): CompletableFuture @CalledInAny diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt index e7d2a0627880..7e351ecd88df 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/data/service/GHPRStateServiceImpl.kt @@ -3,17 +3,17 @@ package org.jetbrains.plugins.github.pullrequest.data.service import com.intellij.collaboration.async.CompletableFutureUtil.submitIOTask import com.intellij.openapi.diagnostic.logger -import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project import org.jetbrains.plugins.github.api.* -import org.jetbrains.plugins.github.api.data.GHBranchProtectionRules +import org.jetbrains.plugins.github.api.data.GHRefUpdateRule import org.jetbrains.plugins.github.api.data.GHRepositoryPermissionLevel import org.jetbrains.plugins.github.api.data.GithubIssueState import org.jetbrains.plugins.github.api.data.GithubPullRequestMergeMethod import org.jetbrains.plugins.github.pullrequest.GHPRStatisticsCollector import org.jetbrains.plugins.github.pullrequest.data.GHPRIdentifier +import org.jetbrains.plugins.github.pullrequest.data.GHPRMergeabilityState import org.jetbrains.plugins.github.pullrequest.data.GHPRMergeabilityStateBuilder import org.jetbrains.plugins.github.pullrequest.data.service.GHServiceUtil.logError import java.util.concurrent.CompletableFuture @@ -28,35 +28,17 @@ class GHPRStateServiceImpl internal constructor(private val progressManager: Pro private val repository = GHRepositoryCoordinates(serverPath, repoPath) - override fun loadBranchProtectionRules(progressIndicator: ProgressIndicator, - pullRequestId: GHPRIdentifier, - baseBranch: String): CompletableFuture { - if (!securityService.currentUserHasPermissionLevel(GHRepositoryPermissionLevel.WRITE)) return CompletableFuture.completedFuture(null) - - return progressManager.submitIOTask(progressIndicator) { - try { - requestExecutor.execute(it, GithubApiRequests.Repos.Branches.getProtection(repository, baseBranch)) - } - catch (e: Exception) { - // assume there are no restrictions - if (e !is ProcessCanceledException) LOG.info("Error occurred while loading branch protection rules for $baseBranch", e) - null - } - } - } - override fun loadMergeabilityState(progressIndicator: ProgressIndicator, pullRequestId: GHPRIdentifier, headRefOid: String, prHtmlUrl: String, - baseBranchProtectionRules: GHBranchProtectionRules?) = + baseRefUpdateRule: GHRefUpdateRule?): CompletableFuture = progressManager.submitIOTask(progressIndicator) { val mergeabilityData = requestExecutor.execute(it, GHGQLRequests.PullRequest.mergeabilityData(repository, pullRequestId.number)) ?: error("Could not find pull request $pullRequestId.number") - val builder = GHPRMergeabilityStateBuilder(headRefOid, prHtmlUrl, - mergeabilityData) - if (baseBranchProtectionRules != null) { - builder.withRestrictions(securityService, baseBranchProtectionRules) + val builder = GHPRMergeabilityStateBuilder(headRefOid, prHtmlUrl, mergeabilityData) + if (baseRefUpdateRule != null) { + builder.withRestrictions(securityService.currentUserHasPermissionLevel(GHRepositoryPermissionLevel.ADMIN), baseRefUpdateRule) } builder.build() }.logError(LOG, "Error occurred while loading mergeability state data for PR ${pullRequestId.number}")