[github] sync GitHub protected branch patterns after fetch (IDEA-191512)

GitOrigin-RevId: 1f33070c18c6e89e0730bb51016421021421cac1
This commit is contained in:
Dmitry Zhuravlev
2020-09-28 15:40:42 +00:00
committed by intellij-monorepo-bot
parent c96d86d9b3
commit 325eab0afd
8 changed files with 139 additions and 3 deletions
@@ -113,6 +113,8 @@
<GitHttpAuthDataProvider implementation="org.jetbrains.plugins.github.extensions.GHHttpAuthDataProvider"/>
<GitHttpAuthDataProvider implementation="org.jetbrains.plugins.github.extensions.GHComHttpAuthDataProvider"/>
<gitRepositoryHostingService implementation="org.jetbrains.plugins.github.extensions.GHRepositoryHostingService"/>
<gitProtectedBranchProvider implementation="org.jetbrains.plugins.github.util.GithubProtectedBranchProvider"/>
<gitFetchHandler implementation="org.jetbrains.plugins.github.extensions.GHProtectedBranchRulesLoader"/>
</extensions>
<actions>
@@ -0,0 +1,13 @@
query($repoOwner: String!, $repoName: String!, $pageSize: Int = 100, $cursor: String) {
repository(owner: $repoOwner, name: $repoName) {
branchProtectionRules(first: $pageSize, after: $cursor) {
pageInfo {
...pageInfo
}
nodes {
...nodeInfo
pattern
}
}
}
}
@@ -391,3 +391,5 @@ pull.request.review.not.supported.non.linear=By-commit review is not supported f
issue.state.open=Open
issue.state.closed=Closed
#protected branches
progress.text.loading.protected.branches=Loading GitHub branch protection rules
@@ -4,6 +4,7 @@ package org.jetbrains.plugins.github.api
object GHGQLQueries {
const val findOrganizationTeams = "findOrganizationTeams"
const val findRepositoryPermission = "findRepositoryPermission"
const val getProtectionRules = "getProtectionRules"
const val commentBody = "commentBody"
const val updateIssueComment = "updateIssueComment"
const val deleteIssueComment = "deleteIssueComment"
@@ -25,4 +26,4 @@ object GHGQLQueries {
const val updateReviewComment = "updateReviewComment"
const val resolveReviewThread = "resolveReviewThread"
const val unresolveReviewThread = "unresolveReviewThread"
}
}
@@ -50,6 +50,20 @@ object GHGQLRequests {
GHRepositoryPermission::class.java,
"repository")
}
fun getProtectionRules(repository: GHRepositoryCoordinates,
pagination: GHGQLRequestPagination? = null): GQLQuery<GHGQLPagedRequestResponse<GHBranchProtectionRule>> {
return GQLQuery.TraversedParsed(repository.serverPath.toGraphQLUrl(), GHGQLQueries.getProtectionRules,
mapOf("repoOwner" to repository.repositoryPath.owner,
"repoName" to repository.repositoryPath.repository,
"pageSize" to pagination?.pageSize,
"cursor" to pagination?.afterCursor),
ProtectedRulesConnection::class.java,
"repository", "branchProtectionRules")
}
private class ProtectedRulesConnection(pageInfo: GHGQLPageInfo, nodes: List<GHBranchProtectionRule>)
: GHConnection<GHBranchProtectionRule>(pageInfo, nodes)
}
object Comment {
@@ -274,4 +288,4 @@ object GHGQLRequests {
"unresolveReviewThread", "thread")
}
}
}
}
@@ -0,0 +1,5 @@
// 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 GHBranchProtectionRule(id: String,
val pattern: String): GHNode(id)
@@ -0,0 +1,83 @@
// 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.extensions
import com.intellij.concurrency.SensitiveProgressWrapper
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project
import com.intellij.util.PatternUtil
import git4idea.config.GitSharedSettings
import git4idea.fetch.GitFetchHandler
import git4idea.repo.GitRemote
import git4idea.repo.GitRepository
import org.jetbrains.plugins.github.api.GHGQLRequests
import org.jetbrains.plugins.github.api.GithubApiRequestExecutorManager
import org.jetbrains.plugins.github.api.util.SimpleGHGQLPagesLoader
import org.jetbrains.plugins.github.authentication.GithubAuthenticationManager
import org.jetbrains.plugins.github.i18n.GithubBundle
import org.jetbrains.plugins.github.util.GHProjectRepositoriesManager
import org.jetbrains.plugins.github.util.GithubSharedProjectSettings
private val LOG = logger<GHProtectedBranchRulesLoader>()
internal class GHProtectedBranchRulesLoader : GitFetchHandler {
override fun doAfterSuccessfulFetch(project: Project, fetches: Map<GitRepository, List<GitRemote>>, indicator: ProgressIndicator) {
try {
loadProtectionRules(indicator, fetches, project)
}
catch (e: Exception) {
if (e is ProcessCanceledException) {
throw e
}
LOG.info("Error occurred while trying to load branch protection rules", e)
}
}
private fun loadProtectionRules(indicator: ProgressIndicator,
fetches: Map<GitRepository, List<GitRemote>>,
project: Project) {
val githubAuthenticationManager = GithubAuthenticationManager.getInstance()
if (!GitSharedSettings.getInstance(project).isSynchronizeBranchProtectionRules || !githubAuthenticationManager.hasAccounts()) {
runInEdt {
GithubSharedProjectSettings.getInstance(project).branchProtectionPatterns = arrayListOf()
}
return
}
indicator.text = GithubBundle.message("progress.text.loading.protected.branches")
val branchProtectionPatterns = mutableSetOf<String>()
for ((repository, remotes) in fetches) {
indicator.checkCanceled()
for (remote in remotes) {
indicator.checkCanceled()
val account =
githubAuthenticationManager.getAccounts().find { it.server.matches(remote.firstUrl.orEmpty()) } ?: continue
val requestExecutor = GithubApiRequestExecutorManager.getInstance().getExecutor(account)
val githubRepositoryMapping =
project.service<GHProjectRepositoriesManager>().findKnownRepositories(repository).find { it.gitRemote.remote == remote }
?: continue
val repositoryCoordinates = githubRepositoryMapping.repository
SimpleGHGQLPagesLoader(requestExecutor, { GHGQLRequests.Repo.getProtectionRules(repositoryCoordinates) })
.loadAll(SensitiveProgressWrapper((indicator)))
.forEach { rule -> branchProtectionPatterns.add(PatternUtil.convertToRegex(rule.pattern)) }
}
}
runInEdt {
GithubSharedProjectSettings.getInstance(project).branchProtectionPatterns = branchProtectionPatterns.toMutableList()
}
}
}
@@ -3,6 +3,8 @@ package org.jetbrains.plugins.github.util
import com.intellij.openapi.components.*
import com.intellij.openapi.project.Project
import git4idea.config.GitProtectedBranchProvider
import java.util.*
@State(name = "GithubSharedProjectSettings", storages = [Storage("vcs.xml")])
class GithubSharedProjectSettings : PersistentStateComponentWithModificationTracker<GithubSharedProjectSettings.SettingsState> {
@@ -10,6 +12,7 @@ class GithubSharedProjectSettings : PersistentStateComponentWithModificationTrac
class SettingsState : BaseState() {
var pullRequestMergeForbidden by property(false)
var branchProtectionPatterns by list<String>()
}
var pullRequestMergeForbidden: Boolean
@@ -18,9 +21,15 @@ class GithubSharedProjectSettings : PersistentStateComponentWithModificationTrac
state.pullRequestMergeForbidden = value
}
var branchProtectionPatterns: MutableList<String>
get() = Collections.unmodifiableList(state.branchProtectionPatterns)
set(value) {
state.branchProtectionPatterns = value
}
override fun getStateModificationCount() = state.modificationCount
override fun getState() = state
override fun loadState(state: GithubSharedProjectSettings.SettingsState) {
override fun loadState(state: SettingsState) {
this.state = state
}
@@ -29,3 +38,10 @@ class GithubSharedProjectSettings : PersistentStateComponentWithModificationTrac
fun getInstance(project: Project) = project.service<GithubSharedProjectSettings>()
}
}
internal class GithubProtectedBranchProvider : GitProtectedBranchProvider {
override fun doGetProtectedBranchPatterns(project: Project): List<String> {
return GithubSharedProjectSettings.getInstance(project).branchProtectionPatterns
}
}