mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
fix [gitlab]: Gitlab rest api calls now use projectId where possible
* GitLabProjectCoordinates are not used as an argument for Api methods anymore * rest api methods use projectId to create request path (except for the initial project request) * initial project request uses encoded `owner/project` to get the path, and expected to be correctly redirected in case if the project was moved * fixes IJPL-81282 by using ID instead of full path in REST API calls * fixes project renaming issue (IJPL-82568) by calling REST endpoint with auto-redirect to get correct project path #IJPL-81282 Fixed #IJPL-82568 Fixed GitOrigin-RevId: 1529c3ddaa855539740a8c192e565e94b8cd9751
This commit is contained in:
committed by
intellij-monorepo-bot
parent
432c6eb55e
commit
da63796d14
+13
-2
@@ -20,11 +20,14 @@ import java.util.UUID
|
||||
|
||||
/**
|
||||
* A low-level helper representing a GitLab project, to which the app was authorized to connect
|
||||
*
|
||||
* @param actualProjectCoordinates coordinates of the project e.g., after rename
|
||||
*/
|
||||
class GitLabProjectConnection(
|
||||
project: Project,
|
||||
private val scope: CoroutineScope,
|
||||
override val repo: GitLabProjectMapping,
|
||||
actualProjectCoordinates: GitLabProjectCoordinates,
|
||||
glProject: GitLabProjectDTO,
|
||||
override val account: GitLabAccount,
|
||||
val currentUser: GitLabUserDTO,
|
||||
@@ -36,9 +39,17 @@ class GitLabProjectConnection(
|
||||
|
||||
val tokenRefreshFlow: Flow<Unit> = tokenState.drop(1).map { }
|
||||
|
||||
val imageLoader: GitLabImageLoader = GitLabImageLoader(apiClient, repo.repository)
|
||||
val imageLoader: GitLabImageLoader = GitLabImageLoader(apiClient)
|
||||
|
||||
val projectData: GitLabProject = GitLabLazyProject(project, scope, apiClient, glMetadata, repo, glProject, currentUser, tokenRefreshFlow)
|
||||
val projectData: GitLabProject = GitLabLazyProject(project,
|
||||
scope,
|
||||
apiClient,
|
||||
glMetadata,
|
||||
glProject,
|
||||
currentUser,
|
||||
tokenRefreshFlow,
|
||||
actualProjectCoordinates,
|
||||
repo.remote)
|
||||
|
||||
val serverVersion: GitLabVersion? = glMetadata?.version
|
||||
|
||||
|
||||
+31
-3
@@ -11,11 +11,14 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.plugins.gitlab.GitLabProjectsManager
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabProjectDTO
|
||||
import org.jetbrains.plugins.gitlab.api.request.findProject
|
||||
import org.jetbrains.plugins.gitlab.api.request.getCurrentUser
|
||||
import org.jetbrains.plugins.gitlab.api.request.getProject
|
||||
import org.jetbrains.plugins.gitlab.authentication.accounts.GitLabAccount
|
||||
import org.jetbrains.plugins.gitlab.authentication.accounts.GitLabAccountManager
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
internal class GitLabProjectConnectionManager(project: Project, cs: CoroutineScope) :
|
||||
@@ -28,12 +31,37 @@ internal class GitLabProjectConnectionManager(project: Project, cs: CoroutineSco
|
||||
{ projectsManager },
|
||||
{ accountManager }
|
||||
) { glProjectMapping, account, tokenState ->
|
||||
val scope = this
|
||||
val apiClient = service<GitLabApiManager>().getClient(account.server) { tokenState.value }
|
||||
val glMetadata = apiClient.getMetadataOrNull()
|
||||
val currentUser = apiClient.graphQL.getCurrentUser()
|
||||
val glProject = apiClient.graphQL.findProject(glProjectMapping.repository).body()
|
||||
?: throw error("Unable to load the project")
|
||||
GitLabProjectConnection(project, this, glProjectMapping, glProject, account, currentUser, apiClient, glMetadata, tokenState)
|
||||
|
||||
var projectCoordinates: GitLabProjectCoordinates = glProjectMapping.repository
|
||||
val projectData: GitLabProjectDTO
|
||||
val originalProject = apiClient.graphQL.findProject(projectCoordinates.projectPath).body()
|
||||
if (originalProject != null) {
|
||||
projectCoordinates = glProjectMapping.repository
|
||||
projectData = originalProject
|
||||
}
|
||||
else {
|
||||
val restProjectResponse = apiClient.rest.getProject(projectCoordinates.projectPath).body()
|
||||
val actualProjectPath = GitLabProjectPath.extractProjectPath(restProjectResponse.pathWithNamespace)
|
||||
?: error("Unable to parse the project path: ${restProjectResponse.pathWithNamespace}")
|
||||
projectCoordinates = projectCoordinates.copy(projectPath = actualProjectPath)
|
||||
projectData = apiClient.graphQL.findProject(actualProjectPath).body()
|
||||
?: error("Could not find the project $actualProjectPath. Check if the project exists and you have access to it.")
|
||||
}
|
||||
|
||||
GitLabProjectConnection(project,
|
||||
scope,
|
||||
glProjectMapping,
|
||||
projectCoordinates,
|
||||
projectData,
|
||||
account,
|
||||
currentUser,
|
||||
apiClient,
|
||||
glMetadata,
|
||||
tokenState)
|
||||
}
|
||||
|
||||
private val delegate = SingleHostedGitRepositoryConnectionManagerImpl(cs, connectionFactory)
|
||||
|
||||
+2
-1
@@ -20,8 +20,9 @@ data class GitLabProjectCoordinates(override val serverPath: GitLabServerPath, v
|
||||
|
||||
companion object {
|
||||
fun create(server: GitLabServerPath, remote: GitRemoteUrlCoordinates): GitLabProjectCoordinates? {
|
||||
val projectPath = GitLabProjectPath.create(server, remote) ?: return null
|
||||
val projectPath = GitLabProjectPath.create(server, remote.url) ?: return null
|
||||
return GitLabProjectCoordinates(server, projectPath)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gitlab.api.dto
|
||||
|
||||
data class GitLabProjectRestDTO(
|
||||
val pathWithNamespace: String,
|
||||
)
|
||||
+25
-17
@@ -16,7 +16,6 @@ import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabGQLQuery
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerMetadata
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabVersion
|
||||
import org.jetbrains.plugins.gitlab.api.SinceGitLab
|
||||
@@ -27,24 +26,26 @@ import org.jetbrains.plugins.gitlab.api.dto.GitLabNamespaceRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabProjectDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabProjectForCloneDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabProjectIsForkedDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabProjectRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabProjectsForCloneDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabRepositoryCreationRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabUserRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabWorkItemDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.WithGitLabNamespace
|
||||
import org.jetbrains.plugins.gitlab.api.gitLabQuery
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUrl
|
||||
import org.jetbrains.plugins.gitlab.api.withErrorStats
|
||||
import org.jetbrains.plugins.gitlab.api.withQuery
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabApiRequestName
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
import java.net.URI
|
||||
import java.net.http.HttpRequest.BodyPublishers
|
||||
import java.net.http.HttpResponse
|
||||
|
||||
@SinceGitLab("12.0")
|
||||
suspend fun GitLabApi.GraphQL.findProject(project: GitLabProjectCoordinates): HttpResponse<out GitLabProjectDTO?> {
|
||||
suspend fun GitLabApi.GraphQL.findProject(projectPath: GitLabProjectPath): HttpResponse<out GitLabProjectDTO?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
)
|
||||
val request = gitLabQuery(GitLabGQLQuery.GET_PROJECT, parameters)
|
||||
return withErrorStats(GitLabGQLQuery.GET_PROJECT) {
|
||||
@@ -71,9 +72,9 @@ suspend fun GitLabApi.Rest.createProject(
|
||||
}
|
||||
|
||||
@SinceGitLab("16.9")
|
||||
private suspend fun GitLabApi.GraphQL.isProjectForked(project: GitLabProjectCoordinates): HttpResponse<out Boolean> {
|
||||
private suspend fun GitLabApi.GraphQL.isProjectForked(projectPath: GitLabProjectPath): HttpResponse<out Boolean> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
)
|
||||
val request = gitLabQuery(GitLabGQLQuery.GET_PROJECT_IS_FORKED, parameters)
|
||||
return withErrorStats(GitLabGQLQuery.GET_PROJECT_IS_FORKED) {
|
||||
@@ -82,28 +83,35 @@ private suspend fun GitLabApi.GraphQL.isProjectForked(project: GitLabProjectCoor
|
||||
}
|
||||
|
||||
@SinceGitLab("12.0")
|
||||
private suspend fun GitLabApi.Rest.isProjectForked(project: GitLabProjectCoordinates): HttpResponse<out GitLabProjectIsForkedDTO> {
|
||||
val uri = project.restApiUri
|
||||
val request = request(uri).GET().build()
|
||||
private suspend fun GitLabApi.Rest.isProjectForked(projectPath: GitLabProjectPath): HttpResponse<out GitLabProjectIsForkedDTO> {
|
||||
val request = request(projectApiUrl(projectPath.fullPath())).GET().build()
|
||||
return withErrorStats(GitLabApiRequestName.REST_GET_PROJECT_IS_FORKED) {
|
||||
loadJsonValue(request)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun GitLabApi.isProjectForked(project: GitLabProjectCoordinates): Boolean =
|
||||
@SinceGitLab("3.0", note = "Not an exact version")
|
||||
suspend fun GitLabApi.Rest.getProject(projectPath: GitLabProjectPath): HttpResponse<out GitLabProjectRestDTO> {
|
||||
val request = request(projectApiUrl(projectPath.fullPath())).GET().build()
|
||||
return withErrorStats(GitLabApiRequestName.REST_GET_PROJECT) {
|
||||
loadJsonValue(request)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun GitLabApi.isProjectForked(projectPath: GitLabProjectPath): Boolean =
|
||||
if (getMetadata().version < GitLabVersion(16, 9)) {
|
||||
rest.isProjectForked(project).body().isForked
|
||||
rest.isProjectForked(projectPath).body().isForked
|
||||
}
|
||||
else {
|
||||
graphQL.isProjectForked(project).body()
|
||||
graphQL.isProjectForked(projectPath).body()
|
||||
}
|
||||
|
||||
|
||||
@SinceGitLab("13.1", note = "No exact version")
|
||||
fun GitLabApi.GraphQL.createAllProjectLabelsFlow(project: GitLabProjectCoordinates): Flow<List<GitLabLabelGQLDTO>> =
|
||||
fun GitLabApi.GraphQL.createAllProjectLabelsFlow(projectPath: GitLabProjectPath): Flow<List<GitLabLabelGQLDTO>> =
|
||||
ApiPageUtil.createGQLPagesFlow { page ->
|
||||
val parameters = page.asParameters() + mapOf(
|
||||
"fullPath" to project.projectPath.fullPath()
|
||||
"fullPath" to projectPath.fullPath()
|
||||
)
|
||||
val request = gitLabQuery(GitLabGQLQuery.GET_PROJECT_LABELS, parameters)
|
||||
withErrorStats(GitLabGQLQuery.GET_PROJECT_LABELS) {
|
||||
@@ -112,10 +120,10 @@ fun GitLabApi.GraphQL.createAllProjectLabelsFlow(project: GitLabProjectCoordinat
|
||||
}.map { it.nodes }
|
||||
|
||||
@SinceGitLab("15.2")
|
||||
fun GitLabApi.GraphQL.createAllWorkItemsFlow(project: GitLabProjectCoordinates): Flow<List<GitLabWorkItemDTO>> =
|
||||
fun GitLabApi.GraphQL.createAllWorkItemsFlow(projectPath: GitLabProjectPath): Flow<List<GitLabWorkItemDTO>> =
|
||||
ApiPageUtil.createGQLPagesFlow { page ->
|
||||
val parameters = page.asParameters() + mapOf(
|
||||
"fullPath" to project.projectPath.fullPath()
|
||||
"fullPath" to projectPath.fullPath()
|
||||
)
|
||||
val request = gitLabQuery(GitLabGQLQuery.GET_PROJECT_WORK_ITEMS, parameters)
|
||||
withErrorStats(GitLabGQLQuery.GET_PROJECT_WORK_ITEMS) {
|
||||
@@ -124,7 +132,7 @@ fun GitLabApi.GraphQL.createAllWorkItemsFlow(project: GitLabProjectCoordinates):
|
||||
}.map { it.nodes }
|
||||
|
||||
@SinceGitLab("7.0", note = "No exact version")
|
||||
fun getProjectUsersURI(project: GitLabProjectCoordinates) = project.restApiUri.resolveRelative("users")
|
||||
fun GitLabApi.Rest.getProjectUsersURI(projectId: String): URI = projectApiUrl(projectId).resolveRelative("users")
|
||||
|
||||
@SinceGitLab("7.0", note = "No exact version")
|
||||
suspend fun GitLabApi.Rest.getProjectUsers(uri: URI): HttpResponse<out List<GitLabUserRestDTO>> {
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
package org.jetbrains.plugins.gitlab.api
|
||||
|
||||
import com.intellij.collaboration.util.resolveRelative
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
import java.net.URI
|
||||
import java.net.URLEncoder
|
||||
|
||||
val GitLabProjectPath.apiId: String
|
||||
get() = URLEncoder.encode("$owner/$name", Charsets.UTF_8)
|
||||
fun GitLabApi.projectApiUrl(projectId: String): URI = server.projectApiUri(URLEncoder.encode(projectId, Charsets.UTF_8))
|
||||
|
||||
val GitLabProjectCoordinates.restApiUri: URI
|
||||
get() = serverPath.restApiUri
|
||||
.resolveRelative("projects/")
|
||||
.resolveRelative(projectPath.apiId + "/")
|
||||
fun GitLabServerPath.projectApiUri(projectId: String): URI = restApiUri
|
||||
.resolveRelative("projects/")
|
||||
.resolveRelative("$projectId/")
|
||||
|
||||
+2
-4
@@ -8,7 +8,6 @@ import com.intellij.util.IconUtil
|
||||
import com.intellij.util.ui.ImageUtil
|
||||
import icons.CollaborationToolsIcons
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO
|
||||
import org.jetbrains.plugins.gitlab.api.request.loadImage
|
||||
import java.awt.Image
|
||||
@@ -22,15 +21,14 @@ private val LOG = logger<GitLabImageLoader>()
|
||||
private const val LOADED_GRAVATAR_SIZE: Int = 80
|
||||
|
||||
class GitLabImageLoader(
|
||||
private val apiClient: GitLabApi,
|
||||
private val gitLabProjectCoordinates: GitLabProjectCoordinates
|
||||
private val apiClient: GitLabApi
|
||||
) : AsyncImageIconsProvider.AsyncImageLoader<GitLabUserDTO>, AsyncHtmlImageLoader {
|
||||
override suspend fun load(key: GitLabUserDTO): Image? {
|
||||
return key.avatarUrl?.let { avatarUrl ->
|
||||
val actualUri = when {
|
||||
avatarUrl.startsWith("http") -> avatarUrl
|
||||
avatarUrl.startsWith("/avatar") -> "https://secure.gravatar.com$avatarUrl?s=$LOADED_GRAVATAR_SIZE&d=identicon"
|
||||
else -> gitLabProjectCoordinates.serverPath.uri + avatarUrl
|
||||
else -> apiClient.server.uri + avatarUrl
|
||||
}
|
||||
load(null, actualUri)
|
||||
}
|
||||
|
||||
+11
-12
@@ -5,13 +5,12 @@ import com.intellij.collaboration.api.json.loadJsonList
|
||||
import com.intellij.collaboration.api.json.loadJsonValue
|
||||
import com.intellij.collaboration.util.resolveRelative
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.SinceGitLab
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabCommitDetailedRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabCommitRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabDiffDTO
|
||||
import org.jetbrains.plugins.gitlab.api.getMetadataOrNull
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUrl
|
||||
import org.jetbrains.plugins.gitlab.api.withErrorStats
|
||||
import org.jetbrains.plugins.gitlab.api.withQuery
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabApiRequestName
|
||||
@@ -19,8 +18,8 @@ import java.net.URI
|
||||
import java.net.http.HttpResponse
|
||||
|
||||
@SinceGitLab("9.0", note = "Not an exact version")
|
||||
suspend fun GitLabApi.getMergeRequestCommitsURI(project: GitLabProjectCoordinates, mrIid: String): URI {
|
||||
return project.restApiUri
|
||||
fun GitLabApi.Rest.getMergeRequestCommitsURI(projectId: String, mrIid: String): URI {
|
||||
return projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("commits")
|
||||
@@ -48,11 +47,11 @@ suspend fun GitLabApi.Rest.loadMergeRequestChanges(uri: URI): HttpResponse<out G
|
||||
}
|
||||
|
||||
@SinceGitLab("9.0", deprecatedIn = "15.7", note = "Deprecated in favour of /diffs")
|
||||
suspend fun GitLabApi.getMergeRequestChangesURI(project: GitLabProjectCoordinates, mrIid: String): URI {
|
||||
suspend fun GitLabApi.Rest.getMergeRequestChangesURI(projectId: String, mrIid: String): URI {
|
||||
val metadata = getMetadataOrNull()
|
||||
requireNotNull(metadata)
|
||||
|
||||
return project.restApiUri
|
||||
return projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("changes")
|
||||
@@ -67,11 +66,11 @@ suspend fun GitLabApi.Rest.loadMergeRequestDiffs(uri: URI): HttpResponse<out Lis
|
||||
}
|
||||
|
||||
@SinceGitLab("15.7")
|
||||
suspend fun GitLabApi.getMergeRequestDiffsURI(project: GitLabProjectCoordinates, mrIid: String, page: Int): URI {
|
||||
suspend fun GitLabApi.Rest.getMergeRequestDiffsURI(projectId: String, mrIid: String, page: Int): URI {
|
||||
val metadata = getMetadataOrNull()
|
||||
requireNotNull(metadata)
|
||||
|
||||
return project.restApiUri
|
||||
return projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("diffs")
|
||||
@@ -89,8 +88,8 @@ suspend fun GitLabApi.Rest.loadCommitDiffs(uri: URI): HttpResponse<out List<GitL
|
||||
}
|
||||
|
||||
@SinceGitLab("7.0")
|
||||
fun getCommitDiffsURI(project: GitLabProjectCoordinates, commitSha: String): URI =
|
||||
project.restApiUri
|
||||
fun GitLabApi.Rest.getCommitDiffsURI(projectId: String, commitSha: String): URI =
|
||||
projectApiUrl(projectId)
|
||||
.resolveRelative("repository")
|
||||
.resolveRelative("commits")
|
||||
.resolveRelative(commitSha)
|
||||
@@ -98,10 +97,10 @@ fun getCommitDiffsURI(project: GitLabProjectCoordinates, commitSha: String): URI
|
||||
|
||||
@SinceGitLab("7.0")
|
||||
suspend fun GitLabApi.Rest.loadCommit(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
commitSha: String,
|
||||
): HttpResponse<out GitLabCommitDetailedRestDTO> {
|
||||
val uri = project.restApiUri
|
||||
val uri = projectApiUrl(projectId)
|
||||
.resolveRelative("repository")
|
||||
.resolveRelative("commits")
|
||||
.resolveRelative(commitSha)
|
||||
|
||||
+20
-22
@@ -12,41 +12,41 @@ import com.intellij.collaboration.util.resolveRelative
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApiUriQueryBuilder
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabGQLQuery
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.SinceGitLab
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabCommitDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabDiscussionRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabNoteRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.gitLabQuery
|
||||
import org.jetbrains.plugins.gitlab.api.loadList
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUrl
|
||||
import org.jetbrains.plugins.gitlab.api.withErrorStats
|
||||
import org.jetbrains.plugins.gitlab.api.withQuery
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabDiffPositionInput
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.dto.LineRangeDTO
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabApiRequestName
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
import java.net.URI
|
||||
import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse
|
||||
|
||||
@SinceGitLab("10.6")
|
||||
suspend fun GitLabApi.Rest.loadMergeRequestDiscussions(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
): HttpResponse<out List<GitLabDiscussionRestDTO>> {
|
||||
val uri = getMergeRequestDiscussionsUri(project, mrIid)
|
||||
val uri = getMergeRequestDiscussionsUri(projectId, mrIid)
|
||||
return loadList(GitLabApiRequestName.REST_GET_MERGE_REQUEST_DISCUSSIONS, uri.toString())
|
||||
}
|
||||
|
||||
|
||||
@SinceGitLab("14.7")
|
||||
suspend fun GitLabApi.GraphQL.loadMergeRequestCommits(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
mrIid: String,
|
||||
pagination: GraphQLRequestPagination? = null
|
||||
): GraphQLConnectionDTO<GitLabCommitDTO>? {
|
||||
val parameters = pagination.orDefault().asParameters() + mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"mriid" to mrIid
|
||||
)
|
||||
val request = gitLabQuery(GitLabGQLQuery.GET_MERGE_REQUEST_COMMITS, parameters)
|
||||
@@ -59,19 +59,19 @@ private class CommitConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List<G
|
||||
: GraphQLConnectionDTO<GitLabCommitDTO>(pageInfo, nodes)
|
||||
|
||||
@SinceGitLab("10.6")
|
||||
fun getMergeRequestDiscussionsUri(project: GitLabProjectCoordinates, mrIid: String): URI =
|
||||
project.restApiUri
|
||||
fun GitLabApi.Rest.getMergeRequestDiscussionsUri(projectId: String, mrIid: String): URI =
|
||||
projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("discussions")
|
||||
|
||||
@SinceGitLab("10.6")
|
||||
suspend fun GitLabApi.Rest.addNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
body: String,
|
||||
): HttpResponse<out GitLabDiscussionRestDTO> {
|
||||
val uri = getMergeRequestDiscussionsUri(project, mrIid).withQuery {
|
||||
val uri = getMergeRequestDiscussionsUri(projectId, mrIid).withQuery {
|
||||
"body" eq body
|
||||
}
|
||||
val request = request(uri).POST(HttpRequest.BodyPublishers.noBody()).build()
|
||||
@@ -82,12 +82,12 @@ suspend fun GitLabApi.Rest.addNote(
|
||||
|
||||
@SinceGitLab("13.2")
|
||||
suspend fun GitLabApi.Rest.addDiffNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
position: GitLabDiffPositionInput,
|
||||
body: String,
|
||||
): HttpResponse<out GitLabDiscussionRestDTO> {
|
||||
val uri = getMergeRequestDiscussionsUri(project, mrIid).withQuery {
|
||||
val uri = getMergeRequestDiscussionsUri(projectId, mrIid).withQuery {
|
||||
"body" eq body
|
||||
addDiffPositionParameters(position)
|
||||
}
|
||||
@@ -99,12 +99,12 @@ suspend fun GitLabApi.Rest.addDiffNote(
|
||||
|
||||
@SinceGitLab("10.6")
|
||||
suspend fun GitLabApi.Rest.createReplyNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
discussionId: String,
|
||||
body: String,
|
||||
): HttpResponse<out GitLabNoteRestDTO> {
|
||||
val uri = getMergeRequestDiscussionsUri(project, mrIid)
|
||||
val uri = getMergeRequestDiscussionsUri(projectId, mrIid)
|
||||
.resolveRelative(discussionId)
|
||||
.resolveRelative("notes")
|
||||
.withQuery {
|
||||
@@ -118,13 +118,13 @@ suspend fun GitLabApi.Rest.createReplyNote(
|
||||
|
||||
@SinceGitLab("10.6")
|
||||
suspend fun GitLabApi.Rest.updateNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
discussionId: String,
|
||||
noteId: String,
|
||||
body: String,
|
||||
): HttpResponse<out GitLabNoteRestDTO> {
|
||||
val uri = getMergeRequestDiscussionsUri(project, mrIid)
|
||||
val uri = getMergeRequestDiscussionsUri(projectId, mrIid)
|
||||
.resolveRelative(discussionId)
|
||||
.resolveRelative("notes")
|
||||
.resolveRelative(noteId)
|
||||
@@ -139,12 +139,12 @@ suspend fun GitLabApi.Rest.updateNote(
|
||||
|
||||
@SinceGitLab("10.6")
|
||||
suspend fun GitLabApi.Rest.deleteNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
discussionId: String,
|
||||
noteId: String,
|
||||
): HttpResponse<out Unit> {
|
||||
val uri = getMergeRequestDiscussionsUri(project, mrIid)
|
||||
val uri = getMergeRequestDiscussionsUri(projectId, mrIid)
|
||||
.resolveRelative(discussionId)
|
||||
.resolveRelative("notes")
|
||||
.resolveRelative(noteId)
|
||||
@@ -156,12 +156,12 @@ suspend fun GitLabApi.Rest.deleteNote(
|
||||
|
||||
@SinceGitLab("10.8")
|
||||
suspend fun GitLabApi.Rest.changeMergeRequestDiscussionResolve(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
discussionId: String,
|
||||
resolved: Boolean,
|
||||
): HttpResponse<out GitLabDiscussionRestDTO> {
|
||||
val uri = getMergeRequestDiscussionsUri(project, mrIid)
|
||||
val uri = getMergeRequestDiscussionsUri(projectId, mrIid)
|
||||
.resolveRelative(discussionId)
|
||||
.withQuery {
|
||||
"resolved" eq resolved
|
||||
@@ -211,5 +211,3 @@ internal fun GitLabApiUriQueryBuilder.addLineRangeParameters(lineRange: LineRang
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+21
-18
@@ -5,10 +5,9 @@ import com.intellij.collaboration.api.json.loadJsonValue
|
||||
import com.intellij.collaboration.util.resolveRelative
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApiUriQueryBuilder
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.SinceGitLab
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabMergeRequestDraftNoteRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUrl
|
||||
import org.jetbrains.plugins.gitlab.api.withErrorStats
|
||||
import org.jetbrains.plugins.gitlab.api.withQuery
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabDiffPositionInput
|
||||
@@ -18,25 +17,29 @@ import java.net.http.HttpRequest.BodyPublishers
|
||||
import java.net.http.HttpResponse
|
||||
|
||||
@SinceGitLab("15.9")
|
||||
fun getMergeRequestDraftNotesUri(project: GitLabProjectCoordinates, mrIid: String): URI =
|
||||
project.restApiUri
|
||||
fun GitLabApi.Rest.getMergeRequestDraftNotesUri(projectId: String, mrIid: String): URI =
|
||||
projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("draft_notes")
|
||||
|
||||
private fun getSpecificMergeRequestDraftNoteUri(project: GitLabProjectCoordinates, mrIid: String, noteId: String): URI =
|
||||
getMergeRequestDraftNotesUri(project, mrIid).resolveRelative(noteId)
|
||||
private fun GitLabApi.Rest.getSpecificMergeRequestDraftNoteUri(
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
noteId: String,
|
||||
): URI =
|
||||
getMergeRequestDraftNotesUri(projectId, mrIid).resolveRelative(noteId)
|
||||
|
||||
@SinceGitLab("15.10")
|
||||
suspend fun GitLabApi.Rest.updateDraftNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
noteId: String,
|
||||
position: GitLabMergeRequestDraftNoteRestDTO.Position,
|
||||
body: String,
|
||||
)
|
||||
: HttpResponse<out Unit> {
|
||||
val uri = getSpecificMergeRequestDraftNoteUri(project, mrIid, noteId).withQuery {
|
||||
val uri = getSpecificMergeRequestDraftNoteUri(projectId, mrIid, noteId).withQuery {
|
||||
"note" eq body
|
||||
addDraftNotePositionParameters(position) // have to pass the existing position, otherwise it is reset to null
|
||||
}
|
||||
@@ -48,12 +51,12 @@ suspend fun GitLabApi.Rest.updateDraftNote(
|
||||
|
||||
@SinceGitLab("15.9")
|
||||
suspend fun GitLabApi.Rest.deleteDraftNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
noteId: Long,
|
||||
)
|
||||
: HttpResponse<out Unit> {
|
||||
val uri = getSpecificMergeRequestDraftNoteUri(project, mrIid, noteId.toString())
|
||||
val uri = getSpecificMergeRequestDraftNoteUri(projectId, mrIid, noteId.toString())
|
||||
val request = request(uri).DELETE().build()
|
||||
return withErrorStats(GitLabApiRequestName.REST_DELETE_DRAFT_NOTE) {
|
||||
sendAndAwaitCancellable(request)
|
||||
@@ -62,11 +65,11 @@ suspend fun GitLabApi.Rest.deleteDraftNote(
|
||||
|
||||
@SinceGitLab("15.11")
|
||||
suspend fun GitLabApi.Rest.submitDraftNotes(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
)
|
||||
: HttpResponse<out Unit> {
|
||||
val uri = getMergeRequestDraftNotesUri(project, mrIid).resolveRelative("bulk_publish")
|
||||
val uri = getMergeRequestDraftNotesUri(projectId, mrIid).resolveRelative("bulk_publish")
|
||||
val request = request(uri).POST(BodyPublishers.noBody()).build()
|
||||
return withErrorStats(GitLabApiRequestName.REST_SUBMIT_DRAFT_NOTES) {
|
||||
sendAndAwaitCancellable(request)
|
||||
@@ -75,11 +78,11 @@ suspend fun GitLabApi.Rest.submitDraftNotes(
|
||||
|
||||
@SinceGitLab("15.10")
|
||||
suspend fun GitLabApi.Rest.submitSingleDraftNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
noteId: Long,
|
||||
): HttpResponse<out Unit> {
|
||||
val uri = getSpecificMergeRequestDraftNoteUri(project, mrIid, noteId.toString()).resolveRelative("publish")
|
||||
val uri = getSpecificMergeRequestDraftNoteUri(projectId, mrIid, noteId.toString()).resolveRelative("publish")
|
||||
val request = request(uri).PUT(BodyPublishers.noBody()).build()
|
||||
return withErrorStats(GitLabApiRequestName.REST_SUBMIT_SINGLE_DRAFT_NOTE) {
|
||||
sendAndAwaitCancellable(request)
|
||||
@@ -88,12 +91,12 @@ suspend fun GitLabApi.Rest.submitSingleDraftNote(
|
||||
|
||||
@SinceGitLab("16.3")
|
||||
suspend fun GitLabApi.Rest.addDraftReplyNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
discussionId: String,
|
||||
body: String,
|
||||
): HttpResponse<out GitLabMergeRequestDraftNoteRestDTO> {
|
||||
val uri = getMergeRequestDraftNotesUri(project, mrIid).withQuery {
|
||||
val uri = getMergeRequestDraftNotesUri(projectId, mrIid).withQuery {
|
||||
"note" eq body
|
||||
"in_reply_to_discussion_id" eq discussionId
|
||||
}
|
||||
@@ -105,13 +108,13 @@ suspend fun GitLabApi.Rest.addDraftReplyNote(
|
||||
|
||||
@SinceGitLab("15.10")
|
||||
suspend fun GitLabApi.Rest.addDraftNote(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
@SinceGitLab("16.3")
|
||||
positionOrNull: GitLabDiffPositionInput?,
|
||||
body: String,
|
||||
): HttpResponse<out GitLabMergeRequestDraftNoteRestDTO> {
|
||||
val uri = getMergeRequestDraftNotesUri(project, mrIid).withQuery {
|
||||
val uri = getMergeRequestDraftNotesUri(projectId, mrIid).withQuery {
|
||||
"note" eq body
|
||||
positionOrNull?.let { addDiffPositionParameters(it) }
|
||||
}
|
||||
|
||||
+7
-8
@@ -4,10 +4,9 @@ package org.jetbrains.plugins.gitlab.mergerequest.api.request
|
||||
import com.intellij.collaboration.api.json.loadJsonValue
|
||||
import com.intellij.collaboration.util.resolveRelative
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.SinceGitLab
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabAwardEmojiRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUrl
|
||||
import org.jetbrains.plugins.gitlab.api.withErrorStats
|
||||
import org.jetbrains.plugins.gitlab.api.withQuery
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabApiRequestName
|
||||
@@ -16,8 +15,8 @@ import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse
|
||||
|
||||
@SinceGitLab("8.9")
|
||||
fun getMRNotesAwardEmojiUri(project: GitLabProjectCoordinates, mrIid: String, noteId: String): URI =
|
||||
project.restApiUri
|
||||
fun GitLabApi.Rest.getMRNotesAwardEmojiUri(projectId: String, mrIid: String, noteId: String): URI =
|
||||
projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("notes")
|
||||
@@ -26,12 +25,12 @@ fun getMRNotesAwardEmojiUri(project: GitLabProjectCoordinates, mrIid: String, no
|
||||
|
||||
@SinceGitLab("8.9")
|
||||
suspend fun GitLabApi.Rest.addAwardEmoji(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
noteId: String,
|
||||
name: String,
|
||||
): HttpResponse<out GitLabAwardEmojiRestDTO> {
|
||||
val uri = getMRNotesAwardEmojiUri(project, mrIid, noteId).withQuery {
|
||||
val uri = getMRNotesAwardEmojiUri(projectId, mrIid, noteId).withQuery {
|
||||
"name" eq name
|
||||
}
|
||||
val request = request(uri).POST(HttpRequest.BodyPublishers.noBody()).build()
|
||||
@@ -42,12 +41,12 @@ suspend fun GitLabApi.Rest.addAwardEmoji(
|
||||
|
||||
@SinceGitLab("8.9")
|
||||
suspend fun GitLabApi.Rest.deleteAwardEmoji(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
noteId: String,
|
||||
awardId: String,
|
||||
): HttpResponse<out Unit> {
|
||||
val uri = getMRNotesAwardEmojiUri(project, mrIid, noteId)
|
||||
val uri = getMRNotesAwardEmojiUri(projectId, mrIid, noteId)
|
||||
.resolveRelative(awardId)
|
||||
val request = request(uri).DELETE().build()
|
||||
return withErrorStats(GitLabApiRequestName.REST_DELETE_NOTE_AWARD_EMOJI) {
|
||||
|
||||
+48
-37
@@ -12,13 +12,12 @@ import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabEdition
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabGQLQuery
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabGidData
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.SinceGitLab
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabGraphQLMutationResultDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabReviewerDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO
|
||||
import org.jetbrains.plugins.gitlab.api.gitLabQuery
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUrl
|
||||
import org.jetbrains.plugins.gitlab.api.withErrorStats
|
||||
import org.jetbrains.plugins.gitlab.api.withQuery
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabMergeRequestByBranchDTO
|
||||
@@ -29,6 +28,7 @@ import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabMergeRequestShort
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequestState
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.asApiParameter
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabApiRequestName
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
import java.net.URI
|
||||
import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse
|
||||
@@ -42,7 +42,7 @@ import java.net.http.HttpResponse
|
||||
*/
|
||||
@SinceGitLab("14.0", note = "No exact version, but definitely exists in minimal")
|
||||
suspend fun GitLabApi.Rest.createMergeRequest(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
sourceBranch: String,
|
||||
targetBranch: String,
|
||||
title: String,
|
||||
@@ -51,7 +51,7 @@ suspend fun GitLabApi.Rest.createMergeRequest(
|
||||
assigneeIds: List<String>? = null,
|
||||
labels: List<String>? = null
|
||||
): HttpResponse<out GitLabMergeRequestShortRestDTO> {
|
||||
val uri = project.restApiUri
|
||||
val uri = projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.withQuery {
|
||||
"source_branch" eq sourceBranch
|
||||
@@ -69,17 +69,19 @@ suspend fun GitLabApi.Rest.createMergeRequest(
|
||||
}
|
||||
|
||||
@SinceGitLab("7.0", note = "?search available since 10.4, ?scope since 9.5")
|
||||
fun getMergeRequestListURI(project: GitLabProjectCoordinates,
|
||||
searchQuery: String): URI =
|
||||
project.restApiUri.resolveRelative("merge_requests").withQuery(searchQuery)
|
||||
fun GitLabApi.Rest.getMergeRequestListURI(
|
||||
projectId: String,
|
||||
searchQuery: String
|
||||
): URI =
|
||||
projectApiUrl(projectId).resolveRelative("merge_requests").withQuery(searchQuery)
|
||||
|
||||
@SinceGitLab("12.0")
|
||||
suspend fun GitLabApi.GraphQL.loadMergeRequest(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
mrIid: String
|
||||
): HttpResponse<out GitLabMergeRequestDTO?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"mergeRequestId" to mrIid
|
||||
)
|
||||
val request = gitLabQuery(GitLabGQLQuery.GET_MERGE_REQUEST, parameters)
|
||||
@@ -91,11 +93,11 @@ suspend fun GitLabApi.GraphQL.loadMergeRequest(
|
||||
@ApiStatus.Internal
|
||||
@SinceGitLab("14.0", note = "No exact version")
|
||||
suspend fun GitLabApi.GraphQL.getMergeRequestMetrics(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
username: String,
|
||||
): HttpResponse<out GitLabMergeRequestMetricsDTO?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"username" to username
|
||||
)
|
||||
val request = gitLabQuery(GitLabGQLQuery.GET_MERGE_REQUEST_METRICS, parameters)
|
||||
@@ -106,13 +108,13 @@ suspend fun GitLabApi.GraphQL.getMergeRequestMetrics(
|
||||
|
||||
@SinceGitLab("13.1")
|
||||
suspend fun GitLabApi.GraphQL.findMergeRequestsByBranch(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
state: GitLabMergeRequestState,
|
||||
sourceBranch: String,
|
||||
targetBranch: String? = null
|
||||
): HttpResponse<out GraphQLConnectionDTO<GitLabMergeRequestByBranchDTO>?> {
|
||||
val parameters = mutableMapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"state" to state.asApiParameter(),
|
||||
"sourceBranches" to listOf(sourceBranch),
|
||||
"targetBranches" to targetBranch?.let { listOf(it) }
|
||||
@@ -127,24 +129,33 @@ private class MergeRequestsByBranchConnection(pageInfo: GraphQLCursorPageInfoDTO
|
||||
: GraphQLConnectionDTO<GitLabMergeRequestByBranchDTO>(pageInfo, nodes)
|
||||
|
||||
@SinceGitLab("13.2")
|
||||
fun getMergeRequestStateEventsUri(project: GitLabProjectCoordinates, mrIid: String): URI =
|
||||
project.restApiUri.resolveRelative("merge_requests").resolveRelative(mrIid).resolveRelative("resource_state_events")
|
||||
fun GitLabApi.Rest.getMergeRequestStateEventsUri(projectId: String, mrIid: String): URI =
|
||||
projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("resource_state_events")
|
||||
|
||||
@SinceGitLab("11.4", note = "Maybe released in 11.3-rc5")
|
||||
fun getMergeRequestLabelEventsUri(project: GitLabProjectCoordinates, mrIid: String): URI =
|
||||
project.restApiUri.resolveRelative("merge_requests").resolveRelative(mrIid).resolveRelative("resource_label_events")
|
||||
fun GitLabApi.Rest.getMergeRequestLabelEventsUri(projectId: String, mrIid: String): URI =
|
||||
projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("resource_label_events")
|
||||
|
||||
@SinceGitLab("13.1")
|
||||
fun getMergeRequestMilestoneEventsUri(project: GitLabProjectCoordinates, mrIid: String): URI =
|
||||
project.restApiUri.resolveRelative("merge_requests").resolveRelative(mrIid).resolveRelative("resource_milestone_events")
|
||||
fun GitLabApi.Rest.getMergeRequestMilestoneEventsUri(projectId: String, mrIid: String): URI =
|
||||
projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("resource_milestone_events")
|
||||
|
||||
@SinceGitLab("10.6", editions = [GitLabEdition.Enterprise])
|
||||
@SinceGitLab("13.3", editions = [GitLabEdition.Community], note = "Maybe released in 13.2-rc42 or so")
|
||||
suspend fun GitLabApi.Rest.mergeRequestApprove(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String
|
||||
): HttpResponse<out Unit> {
|
||||
val uri = project.restApiUri
|
||||
val uri = projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("approve")
|
||||
@@ -157,10 +168,10 @@ suspend fun GitLabApi.Rest.mergeRequestApprove(
|
||||
@SinceGitLab("10.6", editions = [GitLabEdition.Enterprise])
|
||||
@SinceGitLab("13.3", editions = [GitLabEdition.Community], note = "Maybe released in 13.2-rc42 or so")
|
||||
suspend fun GitLabApi.Rest.mergeRequestUnApprove(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String
|
||||
): HttpResponse<out Unit> {
|
||||
val uri = project.restApiUri
|
||||
val uri = projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("unapprove")
|
||||
@@ -172,10 +183,10 @@ suspend fun GitLabApi.Rest.mergeRequestUnApprove(
|
||||
|
||||
@SinceGitLab("11.6")
|
||||
suspend fun GitLabApi.Rest.mergeRequestRebase(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String
|
||||
): HttpResponse<out GitLabMergeRequestRebaseDTO> {
|
||||
val uri = project.restApiUri
|
||||
val uri = projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.resolveRelative("rebase")
|
||||
@@ -187,12 +198,12 @@ suspend fun GitLabApi.Rest.mergeRequestRebase(
|
||||
|
||||
@SinceGitLab("13.9")
|
||||
suspend fun GitLabApi.GraphQL.mergeRequestUpdate(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
mrIid: String,
|
||||
state: GitLabMergeRequestNewState,
|
||||
): HttpResponse<out GitLabGraphQLMutationResultDTO<GitLabMergeRequestDTO>?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"mergeRequestId" to mrIid,
|
||||
"state" to state
|
||||
)
|
||||
@@ -211,12 +222,12 @@ suspend fun GitLabApi.GraphQL.mergeRequestUpdate(
|
||||
*/
|
||||
@SinceGitLab("13.8")
|
||||
suspend fun GitLabApi.Rest.mergeRequestSetReviewers(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectId: String,
|
||||
mrIid: String,
|
||||
reviewers: List<GitLabUserDTO>
|
||||
): HttpResponse<out Unit> {
|
||||
val reviewerIds = reviewers.map { GitLabGidData(it.id).guessRestId() }
|
||||
val uri = project.restApiUri
|
||||
val uri = projectApiUrl(projectId)
|
||||
.resolveRelative("merge_requests")
|
||||
.resolveRelative(mrIid)
|
||||
.withQuery {
|
||||
@@ -238,12 +249,12 @@ suspend fun GitLabApi.Rest.mergeRequestSetReviewers(
|
||||
*/
|
||||
@SinceGitLab("15.3")
|
||||
suspend fun GitLabApi.GraphQL.mergeRequestSetReviewers(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
mrIid: String,
|
||||
reviewers: List<GitLabUserDTO>
|
||||
): HttpResponse<out GitLabGraphQLMutationResultDTO<GitLabMergeRequestDTO>?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"mergeRequestId" to mrIid,
|
||||
"reviewerUsernames" to reviewers.map { it.username }
|
||||
)
|
||||
@@ -255,7 +266,7 @@ suspend fun GitLabApi.GraphQL.mergeRequestSetReviewers(
|
||||
|
||||
@SinceGitLab("13.10")
|
||||
suspend fun GitLabApi.GraphQL.mergeRequestAccept(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
mrIid: String,
|
||||
commitMessage: String,
|
||||
sha: String,
|
||||
@@ -263,7 +274,7 @@ suspend fun GitLabApi.GraphQL.mergeRequestAccept(
|
||||
shouldRemoveSourceBranch: Boolean
|
||||
): HttpResponse<out GitLabGraphQLMutationResultDTO<GitLabMergeRequestDTO>?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"mergeRequestId" to mrIid,
|
||||
"commitMessage" to commitMessage,
|
||||
"sha" to sha,
|
||||
@@ -278,12 +289,12 @@ suspend fun GitLabApi.GraphQL.mergeRequestAccept(
|
||||
|
||||
@SinceGitLab("13.12")
|
||||
suspend fun GitLabApi.GraphQL.mergeRequestSetDraft(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
mrIid: String,
|
||||
isDraft: Boolean
|
||||
): HttpResponse<out GitLabGraphQLMutationResultDTO<GitLabMergeRequestDTO>?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"mergeRequestId" to mrIid,
|
||||
"isDraft" to isDraft
|
||||
)
|
||||
@@ -295,12 +306,12 @@ suspend fun GitLabApi.GraphQL.mergeRequestSetDraft(
|
||||
|
||||
@SinceGitLab("13.9")
|
||||
suspend fun GitLabApi.GraphQL.mergeRequestReviewerRereview(
|
||||
project: GitLabProjectCoordinates,
|
||||
projectPath: GitLabProjectPath,
|
||||
mrIid: String,
|
||||
reviewer: GitLabReviewerDTO
|
||||
): HttpResponse<out GitLabGraphQLMutationResultDTO<GitLabMergeRequestDTO>?> {
|
||||
val parameters = mapOf(
|
||||
"projectId" to project.projectPath.fullPath(),
|
||||
"projectId" to projectPath.fullPath(),
|
||||
"mergeRequestId" to mrIid,
|
||||
"userId" to reviewer.id
|
||||
)
|
||||
|
||||
+5
-6
@@ -33,7 +33,6 @@ import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabRestId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerMetadata
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabVersion
|
||||
@@ -77,7 +76,7 @@ class LoadedGitLabDiscussion(
|
||||
parentCs: CoroutineScope,
|
||||
private val api: GitLabApi,
|
||||
glMetadata: GitLabServerMetadata?,
|
||||
private val glProject: GitLabProjectCoordinates,
|
||||
private val projectId: String,
|
||||
private val currentUser: GitLabUserDTO,
|
||||
private val eventSink: suspend (Change<GitLabDiscussionRestDTO>) -> Unit,
|
||||
private val draftNotesEventSink: suspend (Change<GitLabMergeRequestDraftNoteRestDTO>) -> Unit,
|
||||
@@ -131,7 +130,7 @@ class LoadedGitLabDiscussion(
|
||||
.mapDataToModel(
|
||||
GitLabNoteRestDTO::id,
|
||||
{ note ->
|
||||
MutableGitLabMergeRequestNote(this, api, glProject, mr, id, currentUser, noteEvents::emit, note)
|
||||
MutableGitLabMergeRequestNote(this, api, projectId, mr, id, currentUser, noteEvents::emit, note)
|
||||
},
|
||||
MutableGitLabMergeRequestNote::update
|
||||
).combine(draftNotes) { notes, draftNotes ->
|
||||
@@ -160,7 +159,7 @@ class LoadedGitLabDiscussion(
|
||||
operationsGuard.withLock {
|
||||
val resolved = resolved.first()
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
api.rest.changeMergeRequestDiscussionResolve(glProject, mr.iid, id.restId, !resolved).body()
|
||||
api.rest.changeMergeRequestDiscussionResolve(projectId, mr.iid, id.restId, !resolved).body()
|
||||
}
|
||||
noteEvents.emit(GitLabNoteEvent.Changed(result.notes))
|
||||
if (mr.details.value.targetProject.onlyAllowMergeIfAllDiscussionsAreResolved) {
|
||||
@@ -173,7 +172,7 @@ class LoadedGitLabDiscussion(
|
||||
override suspend fun addNote(body: String) {
|
||||
withContext(cs.coroutineContext) {
|
||||
val note = withContext(Dispatchers.IO) {
|
||||
api.rest.createReplyNote(glProject, mr.iid, id.restId, body).body()
|
||||
api.rest.createReplyNote(projectId, mr.iid, id.restId, body).body()
|
||||
}
|
||||
|
||||
withContext(NonCancellable) {
|
||||
@@ -185,7 +184,7 @@ class LoadedGitLabDiscussion(
|
||||
override suspend fun addDraftNote(body: String) {
|
||||
withContext(cs.coroutineContext) {
|
||||
withContext(Dispatchers.IO) {
|
||||
api.rest.addDraftReplyNote(glProject, mr.iid, id.restId, body).body()
|
||||
api.rest.addDraftReplyNote(projectId, mr.iid, id.restId, body).body()
|
||||
}?.also {
|
||||
withContext(NonCancellable) {
|
||||
draftNotesEventSink(AddedLast(it))
|
||||
|
||||
+36
-29
@@ -14,6 +14,7 @@ import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import git4idea.GitStandardRemoteBranch
|
||||
import git4idea.changes.GitBranchComparisonResult
|
||||
import git4idea.remote.GitRemoteUrlCoordinates
|
||||
import git4idea.remote.hosting.GitRemoteBranchesUtil
|
||||
import git4idea.remote.hosting.changesSignalFlow
|
||||
import git4idea.repo.GitRepository
|
||||
@@ -38,6 +39,7 @@ import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerMetadata
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerPath
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabVersion
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabResourceLabelEventDTO
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabResourceMilestoneEventDTO
|
||||
@@ -62,7 +64,6 @@ import org.jetbrains.plugins.gitlab.mergerequest.api.request.mergeRequestUnAppro
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.request.mergeRequestUpdate
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.loaders.startGitLabRestETagListLoaderIn
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabApiRequestName
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabRegistry
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabStatistics
|
||||
|
||||
@@ -70,8 +71,9 @@ private val LOG = logger<GitLabMergeRequest>()
|
||||
|
||||
@CodeReviewDomainEntity
|
||||
interface GitLabMergeRequest : GitLabMergeRequestDiscussionsContainer {
|
||||
val glProject: GitLabProjectCoordinates
|
||||
val gitRepository: GitRepository
|
||||
val serverPath: GitLabServerPath
|
||||
val gitRemote: GitRemoteUrlCoordinates
|
||||
val projectId: String
|
||||
|
||||
val iid: String
|
||||
val gid: String
|
||||
@@ -142,14 +144,15 @@ internal class LoadedGitLabMergeRequest(
|
||||
parentCs: CoroutineScope,
|
||||
private val api: GitLabApi,
|
||||
private val glMetadata: GitLabServerMetadata?,
|
||||
private val projectMapping: GitLabProjectMapping,
|
||||
private val currentUser: GitLabUserDTO,
|
||||
mergeRequest: GitLabMergeRequestDTO
|
||||
private val projectCoordinates: GitLabProjectCoordinates,
|
||||
override val projectId: String,
|
||||
override val gitRemote: GitRemoteUrlCoordinates,
|
||||
currentUser: GitLabUserDTO,
|
||||
mergeRequest: GitLabMergeRequestDTO,
|
||||
) : GitLabMergeRequest {
|
||||
private val cs = parentCs.childScope(this::class, Dispatchers.Default)
|
||||
|
||||
override val glProject: GitLabProjectCoordinates = projectMapping.repository
|
||||
override val gitRepository: GitRepository = projectMapping.gitRepository
|
||||
override val serverPath: GitLabServerPath = projectCoordinates.serverPath
|
||||
|
||||
override val iid: String = mergeRequest.iid
|
||||
override val gid: String = mergeRequest.id
|
||||
@@ -167,13 +170,16 @@ internal class LoadedGitLabMergeRequest(
|
||||
|
||||
override val changes: SharedFlow<GitLabMergeRequestChanges> = mergeRequestDetailsState
|
||||
.distinctUntilChangedBy(GitLabMergeRequestFullDetails::diffRefs)
|
||||
.mapScoped { details -> GitLabMergeRequestChangesImpl(this, api, glMetadata, projectMapping, details) }
|
||||
.mapScoped { details ->
|
||||
GitLabMergeRequestChangesImpl(this, project, projectId, projectCoordinates.projectPath, gitRemote,
|
||||
api, glMetadata, details)
|
||||
}
|
||||
.modelFlow(cs, LOG)
|
||||
|
||||
override val stateEvents by lazy {
|
||||
startGitLabRestETagListLoaderIn(
|
||||
cs,
|
||||
getMergeRequestStateEventsUri(glProject, iid),
|
||||
api.rest.getMergeRequestStateEventsUri(projectId, iid),
|
||||
{ it.id },
|
||||
|
||||
requestReloadFlow = mergeRequestReloadRequest.withInitial(Unit),
|
||||
@@ -189,7 +195,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
override val labelEvents by lazy {
|
||||
startGitLabRestETagListLoaderIn(
|
||||
cs,
|
||||
getMergeRequestLabelEventsUri(glProject, iid),
|
||||
api.rest.getMergeRequestLabelEventsUri(projectId, iid),
|
||||
{ it.id },
|
||||
|
||||
requestReloadFlow = mergeRequestReloadRequest.withInitial(Unit),
|
||||
@@ -205,7 +211,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
override val milestoneEvents by lazy {
|
||||
startGitLabRestETagListLoaderIn(
|
||||
cs,
|
||||
getMergeRequestMilestoneEventsUri(glProject, iid),
|
||||
api.rest.getMergeRequestMilestoneEventsUri(projectId, iid),
|
||||
{ it.id },
|
||||
|
||||
requestReloadFlow = mergeRequestReloadRequest.withInitial(Unit),
|
||||
@@ -225,7 +231,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
override val draftReviewText: MutableStateFlow<String> = MutableStateFlow("")
|
||||
|
||||
private val discussionsContainer =
|
||||
GitLabMergeRequestDiscussionsContainerImpl(parentCs, project, api, glMetadata, projectMapping.repository, currentUser, this)
|
||||
GitLabMergeRequestDiscussionsContainerImpl(parentCs, project, api, glMetadata, projectId, currentUser, this)
|
||||
|
||||
init {
|
||||
cs.launch {
|
||||
@@ -237,7 +243,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
}
|
||||
|
||||
cs.launch {
|
||||
val repository = projectMapping.gitRepository
|
||||
val repository = gitRemote.repository
|
||||
repository.changesSignalFlow().withInitial(Unit).combine(details) { _, currentDetails ->
|
||||
isCurrentDataInSyncWithRepository(currentDetails, repository)
|
||||
}.distinctUntilChanged().filterNotNull().collectLatest {
|
||||
@@ -255,7 +261,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
detailsLoadingGuard.lock()
|
||||
_isLoading.value = true
|
||||
val updatedMergeRequest = withContext(Dispatchers.IO) {
|
||||
api.graphQL.loadMergeRequest(glProject, iid).body()!!
|
||||
api.graphQL.loadMergeRequest(projectCoordinates.projectPath, iid).body()!!
|
||||
}
|
||||
return updateMergeRequestData(updatedMergeRequest)
|
||||
}
|
||||
@@ -266,7 +272,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
}
|
||||
|
||||
private fun isCurrentDataInSyncWithRepository(details: GitLabMergeRequestFullDetails, repository: GitRepository): Boolean? {
|
||||
val remoteMrBranchHash = details.getSourceRemoteDescriptor(projectMapping.repository.serverPath)?.let {
|
||||
val remoteMrBranchHash = details.getSourceRemoteDescriptor(serverPath)?.let {
|
||||
GitRemoteBranchesUtil.findRemote(repository, it)
|
||||
}?.let {
|
||||
val branch = GitStandardRemoteBranch(it, details.sourceBranch)
|
||||
@@ -329,7 +335,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
override suspend fun approve() {
|
||||
try {
|
||||
withContext(cs.coroutineContext + Dispatchers.IO) {
|
||||
api.rest.mergeRequestApprove(glProject, iid)
|
||||
api.rest.mergeRequestApprove(projectId, iid)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -341,7 +347,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
override suspend fun unApprove() {
|
||||
try {
|
||||
withContext(cs.coroutineContext + Dispatchers.IO) {
|
||||
api.rest.mergeRequestUnApprove(glProject, iid)
|
||||
api.rest.mergeRequestUnApprove(projectId, iid)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -352,7 +358,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
|
||||
override suspend fun close() {
|
||||
withContext(cs.coroutineContext + Dispatchers.IO) {
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestUpdate(glProject, iid, GitLabMergeRequestNewState.CLOSED)
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestUpdate(projectCoordinates.projectPath, iid, GitLabMergeRequestNewState.CLOSED)
|
||||
.getResultOrThrow()
|
||||
updateMergeRequestData(updatedMergeRequest)
|
||||
stateEventsRefreshRequest.emit(Unit)
|
||||
@@ -362,7 +368,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
|
||||
override suspend fun reopen() {
|
||||
withContext(cs.coroutineContext + Dispatchers.IO) {
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestUpdate(glProject, iid, GitLabMergeRequestNewState.OPEN)
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestUpdate(projectCoordinates.projectPath, iid, GitLabMergeRequestNewState.OPEN)
|
||||
.getResultOrThrow()
|
||||
updateMergeRequestData(updatedMergeRequest)
|
||||
stateEventsRefreshRequest.emit(Unit)
|
||||
@@ -372,7 +378,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
|
||||
override suspend fun postReview() {
|
||||
withContext(cs.coroutineContext + Dispatchers.IO) {
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestSetDraft(glProject, iid, isDraft = false)
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestSetDraft(projectCoordinates.projectPath, iid, isDraft = false)
|
||||
.getResultOrThrow()
|
||||
updateMergeRequestData(updatedMergeRequest)
|
||||
}
|
||||
@@ -383,11 +389,11 @@ internal class LoadedGitLabMergeRequest(
|
||||
override suspend fun setReviewers(reviewers: List<GitLabUserDTO>) {
|
||||
withContext(cs.coroutineContext + Dispatchers.IO) {
|
||||
val updatedMergeRequest = if (glMetadata != null && GitLabVersion(15, 3) <= glMetadata.version) {
|
||||
api.graphQL.mergeRequestSetReviewers(glProject, iid, reviewers).getResultOrThrow()
|
||||
api.graphQL.mergeRequestSetReviewers(projectCoordinates.projectPath, iid, reviewers).getResultOrThrow()
|
||||
}
|
||||
else {
|
||||
api.rest.mergeRequestSetReviewers(glProject, iid, reviewers).body()
|
||||
api.graphQL.loadMergeRequest(glProject, iid).body() ?: error("Merge request could not be loaded")
|
||||
api.rest.mergeRequestSetReviewers(projectId, iid, reviewers).body()
|
||||
api.graphQL.loadMergeRequest(projectCoordinates.projectPath, iid).body() ?: error("Merge request could not be loaded")
|
||||
}
|
||||
|
||||
updateMergeRequestData(updatedMergeRequest)
|
||||
@@ -399,7 +405,7 @@ internal class LoadedGitLabMergeRequest(
|
||||
override suspend fun reviewerRereview(reviewers: Collection<GitLabReviewerDTO>) {
|
||||
withContext(cs.coroutineContext + Dispatchers.IO) {
|
||||
reviewers.forEach { reviewer ->
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestReviewerRereview(glProject, iid, reviewer)
|
||||
val updatedMergeRequest = api.graphQL.mergeRequestReviewerRereview(projectCoordinates.projectPath, iid, reviewer)
|
||||
.getResultOrThrow()
|
||||
updateMergeRequestData(updatedMergeRequest)
|
||||
}
|
||||
@@ -442,9 +448,10 @@ internal class LoadedGitLabMergeRequest(
|
||||
val sha = mergeRequestDetailsState.value.diffRefs?.headSha ?: return
|
||||
val shouldRemoveSourceBranch = mergeRequestDetailsState.value.shouldRemoveSourceBranch
|
||||
?: mergeRequestDetailsState.value.targetProject.removeSourceBranchAfterMerge
|
||||
api.graphQL.mergeRequestAccept(glProject, iid, commitMessage, sha, withSquash, shouldRemoveSourceBranch).getResultOrThrow()
|
||||
api.graphQL.mergeRequestAccept(projectCoordinates.projectPath, iid, commitMessage, sha, withSquash, shouldRemoveSourceBranch)
|
||||
.getResultOrThrow()
|
||||
do {
|
||||
val updatedMergeRequest = api.graphQL.loadMergeRequest(glProject, iid).body()!!
|
||||
val updatedMergeRequest = api.graphQL.loadMergeRequest(projectCoordinates.projectPath, iid).body()!!
|
||||
updateMergeRequestData(updatedMergeRequest)
|
||||
delay(GitLabRegistry.getRequestPollingIntervalMillis().toLong())
|
||||
attempts++
|
||||
@@ -454,9 +461,9 @@ internal class LoadedGitLabMergeRequest(
|
||||
|
||||
private suspend fun runRebase() {
|
||||
var attempts = 0
|
||||
api.rest.mergeRequestRebase(glProject, iid)
|
||||
api.rest.mergeRequestRebase(projectId, iid)
|
||||
do {
|
||||
val updatedMergeRequest = api.graphQL.loadMergeRequest(glProject, iid).body()!!
|
||||
val updatedMergeRequest = api.graphQL.loadMergeRequest(projectCoordinates.projectPath, iid).body()!!
|
||||
updateMergeRequestData(updatedMergeRequest)
|
||||
delay(GitLabRegistry.getRequestPollingIntervalMillis().toLong())
|
||||
attempts++
|
||||
|
||||
+23
-16
@@ -7,12 +7,14 @@ import com.intellij.collaboration.async.childScope
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.diff.impl.patch.PatchReader
|
||||
import com.intellij.openapi.diff.impl.patch.TextFilePatch
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vcs.FilePath
|
||||
import com.intellij.openapi.vcs.FileStatus
|
||||
import com.intellij.vcsUtil.VcsFileUtil
|
||||
import git4idea.changes.GitBranchComparisonResult
|
||||
import git4idea.changes.GitCommitShaWithPatches
|
||||
import git4idea.changes.filePath
|
||||
import git4idea.remote.GitRemoteUrlCoordinates
|
||||
import git4idea.remote.hosting.GitCodeReviewUtils
|
||||
import git4idea.repo.GitRepository
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -38,7 +40,7 @@ import org.jetbrains.plugins.gitlab.mergerequest.api.request.loadCommitDiffs
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.request.loadMergeRequestChanges
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.request.loadMergeRequestCommits
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.request.loadMergeRequestDiffs
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
|
||||
private val LOG = logger<GitLabMergeRequestChanges>()
|
||||
|
||||
@@ -74,26 +76,29 @@ internal suspend fun GitLabMergeRequestChanges.loadRevisionsAndParseChanges(): G
|
||||
|
||||
class GitLabMergeRequestChangesImpl(
|
||||
parentCs: CoroutineScope,
|
||||
private val project: Project,
|
||||
private val projectId: String,
|
||||
private val projectPath: GitLabProjectPath,
|
||||
private val gitRemoteUrlCoordinates: GitRemoteUrlCoordinates,
|
||||
private val api: GitLabApi,
|
||||
private val glMetadata: GitLabServerMetadata?,
|
||||
private val projectMapping: GitLabProjectMapping,
|
||||
private val mergeRequestDetails: GitLabMergeRequestFullDetails,
|
||||
) : GitLabMergeRequestChanges {
|
||||
|
||||
private val cs = parentCs.childScope(this::class)
|
||||
|
||||
private val glProject = projectMapping.repository
|
||||
|
||||
private val commits: Deferred<List<GitLabCommit>> = cs.async {
|
||||
if (glMetadata != null && glMetadata.version < GitLabVersion(14, 7)) {
|
||||
val initialURI = api.getMergeRequestCommitsURI(glProject, mergeRequestDetails.iid)
|
||||
val initialURI = api.rest.getMergeRequestCommitsURI(projectId, mergeRequestDetails.iid)
|
||||
return@async ApiPageUtil.createPagesFlowByLinkHeader(initialURI) { uri -> api.rest.loadMergeRequestCommits(uri) }
|
||||
.map { it.body() ?: emptyList() }
|
||||
.foldToList(GitLabCommit.Companion::fromRestDTO)
|
||||
.asReversed()
|
||||
}
|
||||
|
||||
ApiPageUtil.createGQLPagesFlow { pagination -> api.graphQL.loadMergeRequestCommits(glProject, mergeRequestDetails.iid, pagination) }
|
||||
ApiPageUtil.createGQLPagesFlow { pagination ->
|
||||
api.graphQL.loadMergeRequestCommits(projectPath, mergeRequestDetails.iid, pagination)
|
||||
}
|
||||
.map { page -> page.nodes }
|
||||
.foldToList(GitLabCommit.Companion::fromGraphQLDTO)
|
||||
.asReversed()
|
||||
@@ -108,7 +113,6 @@ class GitLabMergeRequestChangesImpl(
|
||||
override suspend fun getParsedChanges(): GitBranchComparisonResult = parsedChanges.await()
|
||||
|
||||
private suspend fun loadChanges(commits: List<GitLabCommit>): GitBranchComparisonResult {
|
||||
val repository = projectMapping.remote.repository
|
||||
val diffRefs = mergeRequestDetails.diffRefs ?: error("Missing diff refs")
|
||||
val baseSha = diffRefs.startSha
|
||||
val mergeBaseSha = diffRefs.baseSha ?: error("Missing merge base revision")
|
||||
@@ -117,8 +121,8 @@ class GitLabMergeRequestChangesImpl(
|
||||
coroutineScope {
|
||||
commits.map { commit ->
|
||||
async {
|
||||
val commitWithParents = api.rest.loadCommit(glProject, commit.sha).body()!!
|
||||
val patches = ApiPageUtil.createPagesFlowByLinkHeader(getCommitDiffsURI(glProject, commit.sha)) {
|
||||
val commitWithParents = api.rest.loadCommit(projectId, commit.sha).body()!!
|
||||
val patches = ApiPageUtil.createPagesFlowByLinkHeader(api.rest.getCommitDiffsURI(projectId, commit.sha)) {
|
||||
api.rest.loadCommitDiffs(it)
|
||||
}.map { it.body() }.foldToList(GitLabDiffDTO::toPatch)
|
||||
GitCommitShaWithPatches(commit.sha, commitWithParents.parentIds, patches)
|
||||
@@ -136,14 +140,14 @@ class GitLabMergeRequestChangesImpl(
|
||||
}
|
||||
val headPatches = withContext(Dispatchers.IO) {
|
||||
if (api.getMetadata().version < GitLabVersion(15, 7)) {
|
||||
ApiPageUtil.createPagesFlowByLinkHeader(api.getMergeRequestChangesURI(glProject, mergeRequestDetails.iid)) {
|
||||
ApiPageUtil.createPagesFlowByLinkHeader(api.rest.getMergeRequestChangesURI(projectId, mergeRequestDetails.iid)) {
|
||||
api.rest.loadMergeRequestChanges(it)
|
||||
}.map { it.body().changes }.foldToList(GitLabDiffDTO::toPatch)
|
||||
}
|
||||
else {
|
||||
// doesn't send back Link headers...
|
||||
ApiPageUtil.createPagesFlowByPagination { page ->
|
||||
api.rest.loadMergeRequestDiffs(api.getMergeRequestDiffsURI(glProject, mergeRequestDetails.iid, page))
|
||||
api.rest.loadMergeRequestDiffs(api.rest.getMergeRequestDiffsURI(projectId, mergeRequestDetails.iid, page))
|
||||
}.map { it.body() }.foldToList(GitLabDiffDTO::toPatch)
|
||||
}
|
||||
}.apply {
|
||||
@@ -153,7 +157,7 @@ class GitLabMergeRequestChangesImpl(
|
||||
}
|
||||
}
|
||||
}
|
||||
return GitBranchComparisonResult.create(repository.project, repository.root, baseSha, mergeBaseSha, commitsWithPatches, headPatches)
|
||||
return GitBranchComparisonResult.create(project, gitRemoteUrlCoordinates.repository.root, baseSha, mergeBaseSha, commitsWithPatches, headPatches)
|
||||
}
|
||||
|
||||
override suspend fun ensureAllRevisionsFetched() {
|
||||
@@ -162,12 +166,15 @@ class GitLabMergeRequestChangesImpl(
|
||||
revsToCheck.add(it)
|
||||
}
|
||||
|
||||
if (GitCodeReviewUtils.testRevisionsExist(projectMapping.gitRepository, revsToCheck)) return
|
||||
if (GitCodeReviewUtils.testRevisionsExist(gitRemoteUrlCoordinates.repository, revsToCheck)) return
|
||||
|
||||
GitCodeReviewUtils.fetch(projectMapping.gitRepository, projectMapping.gitRemote, mergeRequestDetails.targetBranch)
|
||||
GitCodeReviewUtils.fetch(projectMapping.gitRepository, projectMapping.gitRemote, """merge-requests/${mergeRequestDetails.iid}/head:""")
|
||||
GitCodeReviewUtils.fetch(gitRemoteUrlCoordinates.repository, gitRemoteUrlCoordinates.remote, mergeRequestDetails.targetBranch)
|
||||
GitCodeReviewUtils.fetch(gitRemoteUrlCoordinates.repository, gitRemoteUrlCoordinates.remote,
|
||||
"""merge-requests/${mergeRequestDetails.iid}/head:""")
|
||||
|
||||
check(GitCodeReviewUtils.testRevisionsExist(projectMapping.gitRepository, revsToCheck)) { "Failed to fetch some revisions" }
|
||||
check(GitCodeReviewUtils.testRevisionsExist(gitRemoteUrlCoordinates.repository, revsToCheck)) {
|
||||
"Failed to fetch some revisions"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -27,7 +27,6 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerMetadata
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabVersion
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabDiscussionRestDTO
|
||||
@@ -73,7 +72,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
private val project: Project,
|
||||
private val api: GitLabApi,
|
||||
private val glMetadata: GitLabServerMetadata?,
|
||||
private val glProject: GitLabProjectCoordinates,
|
||||
private val projectId: String,
|
||||
private val currentUser: GitLabUserDTO,
|
||||
private val mr: GitLabMergeRequest,
|
||||
) : GitLabMergeRequestDiscussionsContainer {
|
||||
@@ -96,7 +95,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
private val nonEmptyDiscussionsData: SharedFlow<Result<List<GitLabDiscussionRestDTO>>> by lazy {
|
||||
startGitLabRestETagListLoaderIn(
|
||||
cs,
|
||||
getMergeRequestDiscussionsUri(glProject, mr.iid),
|
||||
api.rest.getMergeRequestDiscussionsUri(projectId, mr.iid),
|
||||
{ it.id },
|
||||
|
||||
requestReloadFlow = reloadRequests,
|
||||
@@ -121,7 +120,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
GitLabDiscussionRestDTO::id,
|
||||
{ disc ->
|
||||
LoadedGitLabDiscussion(this,
|
||||
api, glMetadata, glProject, currentUser,
|
||||
api, glMetadata, projectId, currentUser,
|
||||
{ discussionEvents.emit(it) }, { draftNotesEvents.emit(it) },
|
||||
mr, disc, getDiscussionDraftNotes(disc.id).throwFailure())
|
||||
},
|
||||
@@ -155,7 +154,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
else {
|
||||
startGitLabRestETagListLoaderIn(
|
||||
cs,
|
||||
getMergeRequestDraftNotesUri(glProject, mr.iid),
|
||||
api.rest.getMergeRequestDraftNotesUri(projectId, mr.iid),
|
||||
{ it.id },
|
||||
|
||||
requestReloadFlow = reloadRequests,
|
||||
@@ -182,7 +181,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
mapDataToModel(
|
||||
GitLabMergeRequestDraftNoteRestDTO::id,
|
||||
{
|
||||
GitLabMergeRequestDraftNoteImpl(this, api, glMetadata, glProject, mr, { draftNotesEvents.emit(it) }, it, currentUser)
|
||||
GitLabMergeRequestDraftNoteImpl(this, api, glMetadata, projectId, mr, { draftNotesEvents.emit(it) }, it, currentUser)
|
||||
},
|
||||
{ update(it) }
|
||||
)
|
||||
@@ -204,7 +203,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
override suspend fun addNote(body: String) {
|
||||
withContext(cs.coroutineContext) {
|
||||
val newDiscussion = withContext(Dispatchers.IO) {
|
||||
api.rest.addNote(glProject, mr.iid, body).body()
|
||||
api.rest.addNote(projectId, mr.iid, body).body()
|
||||
}
|
||||
|
||||
withContext(NonCancellable) {
|
||||
@@ -216,7 +215,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
override suspend fun addNote(position: GitLabMergeRequestNewDiscussionPosition, body: String) {
|
||||
withContext(cs.coroutineContext) {
|
||||
val newDiscussion = withContext(Dispatchers.IO) {
|
||||
api.rest.addDiffNote(glProject, mr.iid, GitLabDiffPositionInput.from(position), body).body()
|
||||
api.rest.addDiffNote(projectId, mr.iid, GitLabDiffPositionInput.from(position), body).body()
|
||||
}
|
||||
|
||||
withContext(NonCancellable) {
|
||||
@@ -228,7 +227,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
override suspend fun addDraftNote(body: String) {
|
||||
withContext(cs.coroutineContext) {
|
||||
val newNote = withContext(Dispatchers.IO) {
|
||||
api.rest.addDraftNote(glProject, mr.iid, null, body).body()
|
||||
api.rest.addDraftNote(projectId, mr.iid, null, body).body()
|
||||
}
|
||||
|
||||
withContext(NonCancellable) {
|
||||
@@ -240,7 +239,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
override suspend fun addDraftNote(position: GitLabMergeRequestNewDiscussionPosition, body: String) {
|
||||
withContext(cs.coroutineContext) {
|
||||
val newNote = withContext(Dispatchers.IO) {
|
||||
api.rest.addDraftNote(glProject, mr.iid, GitLabDiffPositionInput.from(position), body).body()
|
||||
api.rest.addDraftNote(projectId, mr.iid, GitLabDiffPositionInput.from(position), body).body()
|
||||
}
|
||||
|
||||
withContext(NonCancellable) {
|
||||
@@ -257,7 +256,7 @@ class GitLabMergeRequestDiscussionsContainerImpl(
|
||||
}
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
api.rest.submitDraftNotes(glProject, mr.iid)
|
||||
api.rest.submitDraftNotes(projectId, mr.iid)
|
||||
}
|
||||
withContext(NonCancellable) {
|
||||
draftNotesEvents.emit(AllDeleted())
|
||||
|
||||
+10
-11
@@ -32,7 +32,6 @@ import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabRestId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerMetadata
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabVersion
|
||||
@@ -111,7 +110,7 @@ interface GitLabMergeRequestDraftNote : GitLabMergeRequestNote, MutableGitLabNot
|
||||
class MutableGitLabMergeRequestNote(
|
||||
parentCs: CoroutineScope,
|
||||
private val api: GitLabApi,
|
||||
private val project: GitLabProjectCoordinates,
|
||||
private val projectId: String,
|
||||
private val mr: GitLabMergeRequest,
|
||||
private val discussionId: GitLabRestId,
|
||||
private val currentUser: GitLabUserDTO,
|
||||
@@ -153,7 +152,7 @@ class MutableGitLabMergeRequestNote(
|
||||
withContext(cs.coroutineContext) {
|
||||
operationsGuard.withLock {
|
||||
withContext(Dispatchers.IO) {
|
||||
api.rest.updateNote(project, mr.iid, discussionId.restId, id.restId, newText).body()
|
||||
api.rest.updateNote(projectId, mr.iid, discussionId.restId, id.restId, newText).body()
|
||||
}
|
||||
}
|
||||
data.update { it.copy(body = newText) }
|
||||
@@ -164,7 +163,7 @@ class MutableGitLabMergeRequestNote(
|
||||
withContext(cs.coroutineContext) {
|
||||
operationsGuard.withLock {
|
||||
withContext(Dispatchers.IO) {
|
||||
api.rest.deleteNote(project, mr.iid, discussionId.restId, id.restId).body()
|
||||
api.rest.deleteNote(projectId, mr.iid, discussionId.restId, id.restId).body()
|
||||
}
|
||||
}
|
||||
eventSink(GitLabNoteEvent.Deleted(id))
|
||||
@@ -183,13 +182,13 @@ class MutableGitLabMergeRequestNote(
|
||||
}
|
||||
withContext(Dispatchers.IO) {
|
||||
if (noteEmoji == null) {
|
||||
val awardedEmojiDTO = api.rest.addAwardEmoji(project, mr.iid, id.restId, reaction.name).body()
|
||||
val awardedEmojiDTO = api.rest.addAwardEmoji(projectId, mr.iid, id.restId, reaction.name).body()
|
||||
val awardEmoji = GitLabAwardEmoji.fromDto(awardedEmojiDTO, emojiMap)
|
||||
updateEmojisLocally(awardEmoji)
|
||||
}
|
||||
else {
|
||||
val awardId = noteEmoji.id.restId ?: return@withContext
|
||||
api.rest.deleteAwardEmoji(project, mr.iid, id.restId, awardId).body()
|
||||
api.rest.deleteAwardEmoji(projectId, mr.iid, id.restId, awardId).body()
|
||||
updateEmojisLocally(noteEmoji)
|
||||
}
|
||||
}
|
||||
@@ -213,7 +212,7 @@ class MutableGitLabMergeRequestNote(
|
||||
private suspend fun loadEmojis() {
|
||||
runCatching {
|
||||
val emojiMap = emojiMapDeferred.await()
|
||||
val uri = getMRNotesAwardEmojiUri(project, mr.iid, id.restId)
|
||||
val uri = api.rest.getMRNotesAwardEmojiUri(projectId, mr.iid, id.restId)
|
||||
|
||||
val emojis: List<GitLabAwardEmojiRestDTO> = withContext(Dispatchers.IO) {
|
||||
ApiPageUtil.createPagesFlowByLinkHeader(uri) { pageUri ->
|
||||
@@ -241,7 +240,7 @@ class GitLabMergeRequestDraftNoteImpl(
|
||||
parentCs: CoroutineScope,
|
||||
private val api: GitLabApi,
|
||||
private val glMetadata: GitLabServerMetadata?,
|
||||
private val project: GitLabProjectCoordinates,
|
||||
private val projectId: String,
|
||||
private val mr: GitLabMergeRequest,
|
||||
private val eventSink: suspend (Change<GitLabMergeRequestDraftNoteRestDTO>) -> Unit,
|
||||
private val noteData: GitLabMergeRequestDraftNoteRestDTO,
|
||||
@@ -274,7 +273,7 @@ class GitLabMergeRequestDraftNoteImpl(
|
||||
operationsGuard.withLock {
|
||||
withContext(Dispatchers.IO) {
|
||||
// Checked by canEdit
|
||||
api.rest.updateDraftNote(project, mr.iid, noteData.id.restId, noteData.position, newText)
|
||||
api.rest.updateDraftNote(projectId, mr.iid, noteData.id.restId, noteData.position, newText)
|
||||
}
|
||||
}
|
||||
data.update { it.copy(note = newText) }
|
||||
@@ -287,7 +286,7 @@ class GitLabMergeRequestDraftNoteImpl(
|
||||
withContext(Dispatchers.IO) {
|
||||
// Shouldn't require extra check, delete and get draft notes was introduced in
|
||||
// the same update
|
||||
api.rest.deleteDraftNote(project, mr.iid, noteData.id.restId.toLong()).body()
|
||||
api.rest.deleteDraftNote(projectId, mr.iid, noteData.id.restId.toLong()).body()
|
||||
}
|
||||
}
|
||||
eventSink(Deleted { it.id == id })
|
||||
@@ -300,7 +299,7 @@ class GitLabMergeRequestDraftNoteImpl(
|
||||
withContext(Dispatchers.IO) {
|
||||
// Shouldn't require extra check, delete and get draft notes was introduced in
|
||||
// the same update
|
||||
api.rest.submitSingleDraftNote(project, mr.iid, noteData.id.restId.toLong()).body()
|
||||
api.rest.submitSingleDraftNote(projectId, mr.iid, noteData.id.restId.toLong()).body()
|
||||
}
|
||||
}
|
||||
mr.refreshData()
|
||||
|
||||
+21
-21
@@ -9,6 +9,7 @@ import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.util.coroutines.childScope
|
||||
import com.intellij.util.containers.nullize
|
||||
import git4idea.remote.GitRemoteUrlCoordinates
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
@@ -25,7 +26,6 @@ import kotlinx.coroutines.flow.transformWhile
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabGidData
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabGraphQLMutationException
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerMetadata
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabVersion
|
||||
@@ -43,7 +43,6 @@ import org.jetbrains.plugins.gitlab.mergerequest.api.dto.GitLabMergeRequestDTO
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.request.createMergeRequest
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.request.loadMergeRequest
|
||||
import org.jetbrains.plugins.gitlab.upload.markdownUploadFile
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabRegistry
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabStatistics
|
||||
import java.awt.image.BufferedImage
|
||||
@@ -58,7 +57,9 @@ private val LOG = logger<GitLabProject>()
|
||||
|
||||
@CodeReviewDomainEntity
|
||||
interface GitLabProject {
|
||||
val projectMapping: GitLabProjectMapping
|
||||
val projectCoordinates: GitLabProjectCoordinates
|
||||
val gitRemote: GitRemoteUrlCoordinates
|
||||
val projectId: String
|
||||
|
||||
val dataReloadSignal: SharedFlow<Unit>
|
||||
val mergeRequests: GitLabProjectMergeRequestsStore
|
||||
@@ -69,7 +70,6 @@ interface GitLabProject {
|
||||
fun getMembersBatches(): Flow<List<GitLabUserDTO>>
|
||||
|
||||
val defaultBranch: String?
|
||||
val gitLabProjectId: GitLabId
|
||||
suspend fun isMultipleAssigneesAllowed(): Boolean
|
||||
suspend fun isMultipleReviewersAllowed(): Boolean
|
||||
|
||||
@@ -106,15 +106,16 @@ class GitLabLazyProject(
|
||||
parentCs: CoroutineScope,
|
||||
private val api: GitLabApi,
|
||||
private val glMetadata: GitLabServerMetadata?,
|
||||
override val projectMapping: GitLabProjectMapping,
|
||||
private val initialData: GitLabProjectDTO,
|
||||
private val currentUser: GitLabUserDTO,
|
||||
private val tokenRefreshFlow: Flow<Unit>,
|
||||
override val projectCoordinates: GitLabProjectCoordinates,
|
||||
override val gitRemote: GitRemoteUrlCoordinates,
|
||||
) : GitLabProject {
|
||||
|
||||
private val cs = parentCs.childScope(javaClass.name)
|
||||
|
||||
private val projectCoordinates: GitLabProjectCoordinates = projectMapping.repository
|
||||
override val projectId: String = initialData.id.guessRestId()
|
||||
|
||||
private val _dataReloadSignal = MutableSharedFlow<Unit>(replay = 1)
|
||||
override val dataReloadSignal: SharedFlow<Unit> = _dataReloadSignal.asSharedFlow()
|
||||
@@ -126,20 +127,19 @@ class GitLabLazyProject(
|
||||
loadMultipleAssigneesAllowedFallback()
|
||||
}
|
||||
|
||||
override val gitLabProjectId: GitLabId = initialData.id
|
||||
|
||||
override val mergeRequests by lazy {
|
||||
CachingGitLabProjectMergeRequestsStore(project, cs, api, glMetadata, projectMapping, currentUser, tokenRefreshFlow)
|
||||
override val mergeRequests: GitLabProjectMergeRequestsStore by lazy {
|
||||
CachingGitLabProjectMergeRequestsStore(project, cs, api, glMetadata, currentUser,
|
||||
tokenRefreshFlow, projectCoordinates, projectId, gitRemote)
|
||||
}
|
||||
|
||||
private val labelsLoader = BatchesLoader(cs,
|
||||
api.graphQL.createAllProjectLabelsFlow(projectMapping.repository).map { labels ->
|
||||
api.graphQL.createAllProjectLabelsFlow(projectCoordinates.projectPath).map { labels ->
|
||||
labels.map {
|
||||
GitLabLabel(it.title, it.color)
|
||||
}
|
||||
})
|
||||
private val membersLoader = BatchesLoader(cs,
|
||||
ApiPageUtil.createPagesFlowByLinkHeader(getProjectUsersURI(projectMapping.repository)) {
|
||||
ApiPageUtil.createPagesFlowByLinkHeader(api.rest.getProjectUsersURI(projectId)) {
|
||||
api.rest.getProjectUsers(it)
|
||||
}.map { response -> response.body().map(GitLabUserDTO::fromRestDTO) })
|
||||
|
||||
@@ -189,7 +189,7 @@ class GitLabLazyProject(
|
||||
val assigneeIds = assignees.nullize()?.map { GitLabGidData(it.id).guessRestId() }
|
||||
val labelTitles = labels.nullize()?.map { it.title }
|
||||
val iid = api.rest.createMergeRequest(
|
||||
projectCoordinates,
|
||||
projectId,
|
||||
sourceBranch,
|
||||
targetBranch,
|
||||
title,
|
||||
@@ -200,7 +200,7 @@ class GitLabLazyProject(
|
||||
).body().iid
|
||||
val attempts = GitLabRegistry.getRequestPollingAttempts()
|
||||
repeat(attempts) {
|
||||
val data = api.graphQL.loadMergeRequest(projectCoordinates, iid).body()
|
||||
val data = api.graphQL.loadMergeRequest(projectCoordinates.projectPath, iid).body()
|
||||
if (data?.diffRefs != null) {
|
||||
return@async data
|
||||
}
|
||||
@@ -221,7 +221,7 @@ class GitLabLazyProject(
|
||||
val filename = path.fileName.toString()
|
||||
val mimeType = Files.probeContentType(path) ?: "application/octet-stream"
|
||||
Files.newInputStream(path).use {
|
||||
api.rest.markdownUploadFile(projectCoordinates, filename, mimeType, it).body()
|
||||
api.rest.markdownUploadFile(projectId, filename, mimeType, it).body()
|
||||
}
|
||||
}.await()
|
||||
GitLabStatistics.logFileUploadActionExecuted(project)
|
||||
@@ -235,7 +235,7 @@ class GitLabLazyProject(
|
||||
outputStream.toByteArray()
|
||||
}
|
||||
ByteArrayInputStream(byteArray).use {
|
||||
api.rest.markdownUploadFile(projectCoordinates, "image.png", "image/png", it).body()
|
||||
api.rest.markdownUploadFile(projectId, "image.png", "image/png", it).body()
|
||||
}
|
||||
}.await()
|
||||
GitLabStatistics.logFileUploadActionExecuted(project)
|
||||
@@ -247,10 +247,10 @@ class GitLabLazyProject(
|
||||
}
|
||||
|
||||
private suspend fun getAllowsMultipleAssigneesPropertyFromNamespacePlan() = try {
|
||||
api.rest.getProjectNamespace(projectMapping.repository.projectPath.owner).body()?.plan?.let {
|
||||
api.rest.getProjectNamespace(projectCoordinates.projectPath.owner).body()?.plan?.let {
|
||||
it != GitLabPlan.FREE
|
||||
} ?: run {
|
||||
LOG.warn("Failed to find namespace for project ${projectMapping.repository}")
|
||||
LOG.warn("Failed to find namespace for project ${projectCoordinates.projectPath.fullPath()}")
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -258,13 +258,13 @@ class GitLabLazyProject(
|
||||
throw ce
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn("Failed to load namespace for project ${projectMapping.repository}", e)
|
||||
LOG.warn("Failed to load namespace for project ${projectCoordinates.projectPath.fullPath()}", e)
|
||||
null
|
||||
}
|
||||
|
||||
private suspend fun getAllowsMultipleAssigneesPropertyFromIssueWidget(): Boolean {
|
||||
val widgetAssignees: WorkItemWidgetAssignees? = try {
|
||||
api.graphQL.createAllWorkItemsFlow(projectMapping.repository)
|
||||
api.graphQL.createAllWorkItemsFlow(projectCoordinates.projectPath)
|
||||
.transformWhile { workItems ->
|
||||
val widget = workItems.find { workItem -> workItem.workItemType.name == WorkItemType.ISSUE_TYPE }
|
||||
?.widgets
|
||||
@@ -285,7 +285,7 @@ class GitLabLazyProject(
|
||||
throw ce
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn("Failed to load work item widgets for project ${projectMapping.repository}", e)
|
||||
LOG.warn("Failed to load work item widgets for project ${projectCoordinates.projectPath}", e)
|
||||
return false
|
||||
}
|
||||
return widgetAssignees?.allowsMultipleAssignees ?: false
|
||||
|
||||
+24
-14
@@ -12,6 +12,7 @@ import com.intellij.collaboration.messages.CollaborationToolsBundle
|
||||
import com.intellij.collaboration.util.ResultUtil.runCatchingUser
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import git4idea.remote.GitRemoteUrlCoordinates
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -44,7 +45,6 @@ import org.jetbrains.plugins.gitlab.mergerequest.api.request.getMergeRequestList
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.api.request.loadMergeRequest
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.loaders.startGitLabRestETagListLoaderIn
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabApiRequestName
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
interface GitLabProjectMergeRequestsStore {
|
||||
@@ -75,18 +75,20 @@ interface GitLabProjectMergeRequestsStore {
|
||||
targetBranchName: String? = null): List<GitLabMergeRequestByBranchDTO>
|
||||
}
|
||||
|
||||
class CachingGitLabProjectMergeRequestsStore(private val project: Project,
|
||||
parentCs: CoroutineScope,
|
||||
private val api: GitLabApi,
|
||||
private val glMetadata: GitLabServerMetadata?,
|
||||
private val projectMapping: GitLabProjectMapping,
|
||||
private val currentUser: GitLabUserDTO,
|
||||
private val tokenRefreshFlow: Flow<Unit>) : GitLabProjectMergeRequestsStore {
|
||||
class CachingGitLabProjectMergeRequestsStore(
|
||||
private val project: Project,
|
||||
parentCs: CoroutineScope,
|
||||
private val api: GitLabApi,
|
||||
private val glMetadata: GitLabServerMetadata?,
|
||||
private val currentUser: GitLabUserDTO,
|
||||
private val tokenRefreshFlow: Flow<Unit>,
|
||||
private val projectCoordinates: GitLabProjectCoordinates,
|
||||
private val projectId: String,
|
||||
private val gitRemote: GitRemoteUrlCoordinates,
|
||||
) : GitLabProjectMergeRequestsStore {
|
||||
|
||||
private val cs = parentCs.childScope(this::class)
|
||||
|
||||
private val glProject: GitLabProjectCoordinates = projectMapping.repository
|
||||
|
||||
private val detailsCache = Caffeine.newBuilder()
|
||||
.weakValues()
|
||||
.build<String, GitLabMergeRequestDetails>()
|
||||
@@ -99,7 +101,7 @@ class CachingGitLabProjectMergeRequestsStore(private val project: Project,
|
||||
override fun getListLoaderIn(cs: CoroutineScope, searchQuery: String): ReloadablePotentiallyInfiniteListLoader<GitLabMergeRequestShortRestDTO> {
|
||||
val loader = startGitLabRestETagListLoaderIn(
|
||||
cs,
|
||||
getMergeRequestListURI(glProject, searchQuery),
|
||||
api.rest.getMergeRequestListURI(projectId, searchQuery),
|
||||
{ it.id },
|
||||
|
||||
requestReloadFlow = tokenRefreshFlow.withInitial(Unit),
|
||||
@@ -143,7 +145,15 @@ class CachingGitLabProjectMergeRequestsStore(private val project: Project,
|
||||
.withInitial(iid)
|
||||
.map { mrId -> runCatchingUser { loadMergeRequest(mrId) } } // TODO: create from cached details
|
||||
.transformConsecutiveSuccesses {
|
||||
mapScoped { mrData -> LoadedGitLabMergeRequest(project, this, api, glMetadata, projectMapping, currentUser, mrData) }
|
||||
mapScoped { mrData -> LoadedGitLabMergeRequest(project,
|
||||
this,
|
||||
api,
|
||||
glMetadata,
|
||||
projectCoordinates,
|
||||
projectId,
|
||||
gitRemote,
|
||||
currentUser,
|
||||
mrData) }
|
||||
}
|
||||
.shareIn(cs, SharingStarted.WhileSubscribed(0, 1000), 1)
|
||||
// this the model will only be alive while it's needed
|
||||
@@ -154,7 +164,7 @@ class CachingGitLabProjectMergeRequestsStore(private val project: Project,
|
||||
sourceBranchName: String,
|
||||
targetBranchName: String?): List<GitLabMergeRequestByBranchDTO> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val body = api.graphQL.findMergeRequestsByBranch(projectMapping.repository, state, sourceBranchName, targetBranchName).body()
|
||||
val body = api.graphQL.findMergeRequestsByBranch(projectCoordinates.projectPath, state, sourceBranchName, targetBranchName).body()
|
||||
body!!.nodes
|
||||
}
|
||||
|
||||
@@ -167,7 +177,7 @@ class CachingGitLabProjectMergeRequestsStore(private val project: Project,
|
||||
@Throws(HttpStatusErrorException::class, IllegalStateException::class)
|
||||
private suspend fun loadMergeRequest(iid: String): GitLabMergeRequestDTO {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val body = api.graphQL.loadMergeRequest(glProject, iid).body()
|
||||
val body = api.graphQL.loadMergeRequest(projectCoordinates.projectPath, iid).body()
|
||||
if (body == null) {
|
||||
api.rest.getCurrentUser() // Exception is generated automatically if status code >= 400
|
||||
error(CollaborationToolsBundle.message("graphql.errors", "empty response"))
|
||||
|
||||
+11
-5
@@ -49,10 +49,14 @@ internal class GitLabMergeRequestViewModels(
|
||||
private val openMergeRequestTimeline: (String, Boolean) -> Unit,
|
||||
private val openMergeRequestDiff: (String, Boolean) -> Unit,
|
||||
) {
|
||||
private val htmlConverter: GitLabMarkdownToHtmlConverter = GitLabMarkdownToHtmlConverter(project,
|
||||
projectData.projectMapping.gitRepository,
|
||||
projectData.projectMapping.repository,
|
||||
projectData.gitLabProjectId)
|
||||
private val htmlConverter: GitLabMarkdownToHtmlConverter =
|
||||
GitLabMarkdownToHtmlConverter(
|
||||
project,
|
||||
projectData.gitRemote.repository,
|
||||
projectData.projectCoordinates.serverPath,
|
||||
projectData.projectId,
|
||||
projectData.projectCoordinates.projectPath
|
||||
)
|
||||
|
||||
private val cs = parentCs.childScope(javaClass.name)
|
||||
|
||||
@@ -82,7 +86,9 @@ internal class GitLabMergeRequestViewModels(
|
||||
val diffVm: GitLabMergeRequestDiffViewModel get() = _diffVm
|
||||
|
||||
val editorReviewVm: GitLabMergeRequestEditorReviewViewModel by lazy {
|
||||
GitLabMergeRequestEditorReviewViewModel(cs, project, projectData.projectMapping, currentUser, mergeRequest,
|
||||
GitLabMergeRequestEditorReviewViewModel(cs, project,
|
||||
projectData.gitRemote, projectData.projectCoordinates,
|
||||
currentUser, mergeRequest,
|
||||
discussionsVms, avatarIconProvider, imageLoader,
|
||||
openMergeRequestDetails, openMergeRequestDiff).apply {
|
||||
setup()
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ import javax.swing.JComponent
|
||||
|
||||
internal object GitLabMergeRequestCreateComponentFactory {
|
||||
fun create(project: Project, cs: CoroutineScope, createVm: GitLabMergeRequestCreateViewModel): JComponent {
|
||||
val directionModel = GitLabMergeRequestCreateDirectionModel(createVm.projectsManager, createVm.projectData.projectMapping)
|
||||
val directionModel = GitLabMergeRequestCreateDirectionModel(createVm)
|
||||
cs.launchNow {
|
||||
createVm.branchState.filterNotNull().collect { branchState ->
|
||||
directionModel.baseBranch = branchState.baseBranch
|
||||
|
||||
+3
-5
@@ -5,15 +5,13 @@ import com.intellij.collaboration.ui.SimpleEventListener
|
||||
import com.intellij.util.EventDispatcher
|
||||
import git4idea.GitBranch
|
||||
import git4idea.GitRemoteBranch
|
||||
import git4idea.remote.hosting.knownRepositories
|
||||
import git4idea.ui.branch.MergeDirectionModel
|
||||
import org.jetbrains.plugins.gitlab.GitLabProjectsManager
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
|
||||
internal class GitLabMergeRequestCreateDirectionModel(
|
||||
private val repositoriesManager: GitLabProjectsManager,
|
||||
override val baseRepo: GitLabProjectMapping
|
||||
private val createVm: GitLabMergeRequestCreateViewModel
|
||||
) : MergeDirectionModel<GitLabProjectMapping> {
|
||||
override val baseRepo: GitLabProjectMapping = createVm.projectMapping
|
||||
private val changeEventDispatcher = EventDispatcher.create(SimpleEventListener::class.java)
|
||||
|
||||
override var baseBranch: GitRemoteBranch? = null
|
||||
@@ -37,7 +35,7 @@ internal class GitLabMergeRequestCreateDirectionModel(
|
||||
}
|
||||
|
||||
override fun getKnownRepoMappings(): List<GitLabProjectMapping> {
|
||||
return repositoriesManager.knownRepositories.toList()
|
||||
return createVm.getAllKnownProjects()
|
||||
}
|
||||
|
||||
override fun setHead(repo: GitLabProjectMapping?, branch: GitBranch?) {
|
||||
|
||||
+12
-7
@@ -28,6 +28,7 @@ import git4idea.GitRemoteBranch
|
||||
import git4idea.config.GitSharedSettings
|
||||
import git4idea.history.GitLogUtil
|
||||
import git4idea.remote.hosting.changesSignalFlow
|
||||
import git4idea.remote.hosting.knownRepositories
|
||||
import git4idea.repo.GitRepository
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -44,7 +45,6 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChangedBy
|
||||
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
@@ -61,8 +61,7 @@ import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabStatistics
|
||||
|
||||
internal interface GitLabMergeRequestCreateViewModel : CodeReviewTitleDescriptionViewModel {
|
||||
val projectsManager: GitLabProjectsManager
|
||||
val projectData: GitLabProject
|
||||
val projectMapping: GitLabProjectMapping
|
||||
val avatarIconProvider: IconsProvider<GitLabUserDTO>
|
||||
|
||||
val titleGenerationVm: StateFlow<GitLabMergeRequestCreateTitleGenerationViewModel?>
|
||||
@@ -91,6 +90,8 @@ internal interface GitLabMergeRequestCreateViewModel : CodeReviewTitleDescriptio
|
||||
|
||||
fun updateBranchState(state: BranchState?)
|
||||
|
||||
fun getAllKnownProjects(): List<GitLabProjectMapping>
|
||||
|
||||
fun setReviewers(reviewers: List<GitLabUserDTO>)
|
||||
fun setAssignees(assignees: List<GitLabUserDTO>)
|
||||
fun setLabels(labels: List<GitLabLabel>)
|
||||
@@ -102,8 +103,8 @@ internal interface GitLabMergeRequestCreateViewModel : CodeReviewTitleDescriptio
|
||||
internal class GitLabMergeRequestCreateViewModelImpl(
|
||||
private val project: Project,
|
||||
parentCs: CoroutineScope,
|
||||
override val projectsManager: GitLabProjectsManager,
|
||||
override val projectData: GitLabProject,
|
||||
private val projectsManager: GitLabProjectsManager,
|
||||
private val projectData: GitLabProject,
|
||||
override val avatarIconProvider: IconsProvider<GitLabUserDTO>,
|
||||
override val openReviewTabAction: suspend (mrIid: String) -> Unit,
|
||||
private val onReviewCreated: () -> Unit,
|
||||
@@ -158,7 +159,9 @@ internal class GitLabMergeRequestCreateViewModelImpl(
|
||||
}?.iid
|
||||
}
|
||||
|
||||
private val gitRepository: GitRepository = projectData.projectMapping.gitRepository
|
||||
private val gitRepository: GitRepository = projectData.gitRemote.repository
|
||||
override val projectMapping: GitLabProjectMapping = GitLabProjectMapping(projectData.projectCoordinates, projectData.gitRemote)
|
||||
|
||||
private val commitRevisionComparisonFlow: Flow<CommitRevisionComparison?> =
|
||||
combine(gitRepository.changesSignalFlow().withInitial(Unit), branchState) { _, state -> state }
|
||||
.map { state ->
|
||||
@@ -240,7 +243,7 @@ internal class GitLabMergeRequestCreateViewModelImpl(
|
||||
|
||||
init {
|
||||
cs.launch {
|
||||
val baseRepo = projectData.projectMapping
|
||||
val baseRepo = GitLabProjectMapping(projectData.projectCoordinates, projectData.gitRemote)
|
||||
val baseGitRepo = baseRepo.gitRepository
|
||||
val defaultBranch = projectData.defaultBranch ?: return@launch
|
||||
val baseBranch = baseGitRepo.getBranchTrackInfo(defaultBranch)?.remoteBranch ?: return@launch
|
||||
@@ -277,6 +280,8 @@ internal class GitLabMergeRequestCreateViewModelImpl(
|
||||
_branchState.value = state
|
||||
}
|
||||
|
||||
override fun getAllKnownProjects(): List<GitLabProjectMapping> = projectsManager.knownRepositories.toList()
|
||||
|
||||
override fun setReviewers(reviewers: List<GitLabUserDTO>) {
|
||||
_reviewers.value = reviewers
|
||||
GitLabStatistics.logMrCreationReviewersAdjusted(project)
|
||||
|
||||
+13
-13
@@ -9,9 +9,9 @@ import com.intellij.collaboration.ui.codereview.details.model.CodeReviewBranches
|
||||
import com.intellij.collaboration.ui.codereview.details.model.CodeReviewBranchesViewModel
|
||||
import com.intellij.dvcs.DvcsUtil
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import git4idea.remote.GitRemoteUrlCoordinates
|
||||
import git4idea.remote.hosting.GitRemoteBranchesUtil
|
||||
import git4idea.remote.hosting.changesSignalFlow
|
||||
import git4idea.repo.GitRepository
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
@@ -19,20 +19,20 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerPath
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequest
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequestFullDetails
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.getSourceRemoteDescriptor
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.getSpecialRemoteBranchForHead
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.util.GitLabMergeRequestBranchUtil
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabStatistics
|
||||
|
||||
internal class GitLabMergeRequestBranchesViewModel(
|
||||
parentCs: CoroutineScope,
|
||||
private val mergeRequest: GitLabMergeRequest,
|
||||
private val mapping: GitLabProjectMapping
|
||||
private val serverPath: GitLabServerPath,
|
||||
private val gitRemote: GitRemoteUrlCoordinates,
|
||||
) : CodeReviewBranchesViewModel {
|
||||
private val gitRepository: GitRepository = mapping.remote.repository
|
||||
|
||||
private val cs: CoroutineScope = parentCs.childScope(this::class)
|
||||
|
||||
@@ -48,15 +48,15 @@ internal class GitLabMergeRequestBranchesViewModel(
|
||||
return "$sourceProjectOwner:${details.sourceBranch}"
|
||||
}
|
||||
|
||||
override val isCheckedOut: SharedFlow<Boolean> = gitRepository.changesSignalFlow().withInitial(Unit)
|
||||
override val isCheckedOut: SharedFlow<Boolean> = gitRemote.repository.changesSignalFlow().withInitial(Unit)
|
||||
.combine(mergeRequest.details) { _, details ->
|
||||
val sourceRemote = details.getSourceRemoteDescriptor(mapping.repository.serverPath)
|
||||
val sourceRemote = details.getSourceRemoteDescriptor(serverPath)
|
||||
if (sourceRemote != null) {
|
||||
GitRemoteBranchesUtil.isRemoteBranchCheckedOut(gitRepository, sourceRemote, details.sourceBranch)
|
||||
GitRemoteBranchesUtil.isRemoteBranchCheckedOut(gitRemote.repository, sourceRemote, details.sourceBranch)
|
||||
}
|
||||
else {
|
||||
val specialRef = details.getSpecialRemoteBranchForHead(mapping.gitRemote)
|
||||
GitRemoteBranchesUtil.isRemoteBranchCheckedOut(gitRepository, specialRef)
|
||||
val specialRef = details.getSpecialRemoteBranchForHead(gitRemote.remote)
|
||||
GitRemoteBranchesUtil.isRemoteBranchCheckedOut(gitRemote.repository, specialRef)
|
||||
}
|
||||
}.modelFlow(cs, thisLogger())
|
||||
|
||||
@@ -66,18 +66,18 @@ internal class GitLabMergeRequestBranchesViewModel(
|
||||
override fun fetchAndCheckoutRemoteBranch() {
|
||||
cs.launch {
|
||||
val details = mergeRequest.details.first()
|
||||
GitLabMergeRequestBranchUtil.fetchAndCheckoutBranch(mapping, details)
|
||||
GitLabMergeRequestBranchUtil.fetchAndCheckoutBranch(gitRemote.repository, serverPath, details)
|
||||
}
|
||||
GitLabStatistics.logMrActionExecuted(gitRepository.project, GitLabStatistics.MergeRequestAction.BRANCH_CHECKOUT)
|
||||
GitLabStatistics.logMrActionExecuted(gitRemote.repository.project, GitLabStatistics.MergeRequestAction.BRANCH_CHECKOUT)
|
||||
}
|
||||
|
||||
override val canShowInLog: Boolean = true
|
||||
override fun fetchAndShowInLog() {
|
||||
cs.launch {
|
||||
val details = mergeRequest.details.first()
|
||||
GitLabMergeRequestBranchUtil.fetchAndShowRemoteBranchInLog(mapping, details)
|
||||
GitLabMergeRequestBranchUtil.fetchAndShowRemoteBranchInLog(gitRemote.repository, serverPath, details)
|
||||
}
|
||||
GitLabStatistics.logMrActionExecuted(gitRepository.project, GitLabStatistics.MergeRequestAction.SHOW_BRANCH_IN_LOG)
|
||||
GitLabStatistics.logMrActionExecuted(gitRemote.repository.project, GitLabStatistics.MergeRequestAction.SHOW_BRANCH_IN_LOG)
|
||||
}
|
||||
|
||||
override fun showBranches() {
|
||||
|
||||
+6
-6
@@ -69,11 +69,11 @@ internal class GitLabMergeRequestChangeListViewModelImpl(
|
||||
persistentChangesViewedState.updatesFlow.withInitial(Unit),
|
||||
) { discPos, draftsPos, _ ->
|
||||
changes.associateWith { change ->
|
||||
val sha = parsedChanges.findLatestCommitWithChangesTo(mergeRequest.gitRepository, change.filePath)
|
||||
val sha = parsedChanges.findLatestCommitWithChangesTo(mergeRequest.gitRemote.repository, change.filePath)
|
||||
val isRead = !isOnLatest || sha?.let {
|
||||
persistentChangesViewedState.isViewed(
|
||||
mergeRequest.glProject, mergeRequest.iid,
|
||||
mergeRequest.gitRepository,
|
||||
mergeRequest.serverPath, mergeRequest.projectId, mergeRequest.iid,
|
||||
mergeRequest.gitRemote.repository,
|
||||
change.filePath, it
|
||||
)
|
||||
} ?: false
|
||||
@@ -104,13 +104,13 @@ internal class GitLabMergeRequestChangeListViewModelImpl(
|
||||
override fun setViewedState(changes: Iterable<RefComparisonChange>, viewed: Boolean) {
|
||||
val filePathsWithShas = changes.mapNotNull { change ->
|
||||
val path = change.filePath
|
||||
parsedChanges.findLatestCommitWithChangesTo(mergeRequest.gitRepository, path)?.let {
|
||||
parsedChanges.findLatestCommitWithChangesTo(mergeRequest.gitRemote.repository, path)?.let {
|
||||
path to it
|
||||
}
|
||||
}
|
||||
persistentChangesViewedState.markViewed(
|
||||
mergeRequest.glProject, mergeRequest.iid,
|
||||
mergeRequest.gitRepository,
|
||||
mergeRequest.serverPath, mergeRequest.projectId, mergeRequest.iid,
|
||||
mergeRequest.gitRemote.repository,
|
||||
filePathsWithShas,
|
||||
viewed
|
||||
)
|
||||
|
||||
+14
-4
@@ -50,7 +50,7 @@ internal class GitLabMergeRequestDetailsViewModelImpl(
|
||||
currentUser: GitLabUserDTO,
|
||||
projectData: GitLabProject,
|
||||
private val mergeRequest: GitLabMergeRequest,
|
||||
private val avatarIconsProvider: IconsProvider<GitLabUserDTO>,
|
||||
avatarIconsProvider: IconsProvider<GitLabUserDTO>,
|
||||
htmlConverter: GitLabMarkdownToHtmlConverter,
|
||||
) : GitLabMergeRequestDetailsViewModel {
|
||||
|
||||
@@ -86,9 +86,19 @@ internal class GitLabMergeRequestDetailsViewModelImpl(
|
||||
override val detailsReviewFlowVm = GitLabMergeRequestReviewFlowViewModelImpl(
|
||||
project, cs, currentUser, projectData, mergeRequest, avatarIconsProvider
|
||||
)
|
||||
override val branchesVm = GitLabMergeRequestBranchesViewModel(cs, mergeRequest, projectData.projectMapping)
|
||||
override val statusVm = GitLabMergeRequestStatusViewModelImpl(project, cs, projectData.projectMapping.gitRepository,
|
||||
projectData.projectMapping.repository.serverPath, mergeRequest)
|
||||
override val branchesVm = GitLabMergeRequestBranchesViewModel(
|
||||
cs,
|
||||
mergeRequest,
|
||||
projectData.projectCoordinates.serverPath,
|
||||
projectData.gitRemote
|
||||
)
|
||||
override val statusVm = GitLabMergeRequestStatusViewModelImpl(
|
||||
project,
|
||||
cs,
|
||||
projectData.gitRemote.repository,
|
||||
projectData.projectCoordinates.serverPath,
|
||||
mergeRequest
|
||||
)
|
||||
override val changesVm = GitLabMergeRequestChangesViewModelImpl(project, cs, mergeRequest, htmlConverter)
|
||||
|
||||
override fun reloadData() {
|
||||
|
||||
+21
-11
@@ -14,7 +14,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerPath
|
||||
import java.time.Duration
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
@@ -40,7 +40,8 @@ internal class GitLabPersistentMergeRequestChangesViewedState
|
||||
|
||||
@Serializable
|
||||
data class MRId(
|
||||
val project: GitLabProjectCoordinates,
|
||||
val serverPath: GitLabServerPath,
|
||||
val projectId: String,
|
||||
val iid: String
|
||||
)
|
||||
|
||||
@@ -55,22 +56,31 @@ internal class GitLabPersistentMergeRequestChangesViewedState
|
||||
val viewedFiles: Map<String, String> = mapOf()
|
||||
)
|
||||
|
||||
fun isViewed(glProject: GitLabProjectCoordinates, iid: String,
|
||||
gitRepository: GitRepository,
|
||||
filePath: FilePath, sha: String): Boolean {
|
||||
fun isViewed(
|
||||
serverPath: GitLabServerPath,
|
||||
projectId: String,
|
||||
iid: String,
|
||||
gitRepository: GitRepository,
|
||||
filePath: FilePath,
|
||||
sha: String,
|
||||
): Boolean {
|
||||
val relPath = VcsFileUtil.relativePath(gitRepository.root, filePath)
|
||||
|
||||
return state.statesMap[MRId(glProject, iid)]?.let {
|
||||
return state.statesMap[MRId(serverPath, projectId, iid)]?.let {
|
||||
it.viewedFiles[relPath] == sha
|
||||
} ?: false
|
||||
}
|
||||
|
||||
fun markViewed(glProject: GitLabProjectCoordinates, iid: String,
|
||||
gitRepository: GitRepository,
|
||||
filePathsAndShas: Iterable<Pair<FilePath, String>>,
|
||||
viewed: Boolean) {
|
||||
fun markViewed(
|
||||
serverPath: GitLabServerPath,
|
||||
projectId: String,
|
||||
iid: String,
|
||||
gitRepository: GitRepository,
|
||||
filePathsAndShas: Iterable<Pair<FilePath, String>>,
|
||||
viewed: Boolean,
|
||||
) {
|
||||
val relPathsAndShas = filePathsAndShas.map { VcsFileUtil.relativePath(gitRepository.root, it.first) to it.second }
|
||||
updateStateOrCreateAndCleanup(MRId(glProject, iid)) { st ->
|
||||
updateStateOrCreateAndCleanup(MRId(serverPath, projectId, iid)) { st ->
|
||||
if (viewed) {
|
||||
MRViewedState(id = st.id, viewedFiles = st.viewedFiles + relPathsAndShas)
|
||||
}
|
||||
|
||||
+2
-2
@@ -119,8 +119,8 @@ internal class GitLabMergeRequestDiffReviewViewModelImpl(
|
||||
override fun markViewed() {
|
||||
val sha = mergeRequest.details.value.diffRefs?.headSha ?: return
|
||||
persistentChangesViewedState.markViewed(
|
||||
mergeRequest.glProject, mergeRequest.iid,
|
||||
mergeRequest.gitRepository,
|
||||
mergeRequest.serverPath, mergeRequest.projectId, mergeRequest.iid,
|
||||
mergeRequest.gitRemote.repository,
|
||||
listOf(change.filePath to sha),
|
||||
true
|
||||
)
|
||||
|
||||
+10
-5
@@ -30,7 +30,9 @@ import com.intellij.util.EventDispatcher
|
||||
import git4idea.branch.GitBranchSyncStatus
|
||||
import git4idea.changes.GitBranchComparisonResult
|
||||
import git4idea.changes.GitTextFilePatchWithHistory
|
||||
import git4idea.remote.GitRemoteUrlCoordinates
|
||||
import git4idea.remote.hosting.localCommitsSyncStatus
|
||||
import git4idea.repo.GitRepository
|
||||
import git4idea.ui.branch.GitCurrentBranchPresenter
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -55,6 +57,7 @@ import kotlinx.coroutines.flow.transformLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO
|
||||
import org.jetbrains.plugins.gitlab.data.GitLabImageLoader
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.GitLabMergeRequestsPreferences
|
||||
@@ -63,7 +66,6 @@ import org.jetbrains.plugins.gitlab.mergerequest.ui.createDiffDataFlow
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.ui.review.GitLabMergeRequestDiscussionsViewModels
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.ui.review.GitLabMergeRequestReviewViewModelBase
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.util.GitLabMergeRequestBranchUtil
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabStatistics
|
||||
import java.util.EventListener
|
||||
|
||||
@@ -73,7 +75,8 @@ private val LOG = logger<GitLabMergeRequestEditorReviewViewModel>()
|
||||
class GitLabMergeRequestEditorReviewViewModel internal constructor(
|
||||
parentCs: CoroutineScope,
|
||||
private val project: Project,
|
||||
private val projectMapping: GitLabProjectMapping,
|
||||
gitRemote: GitRemoteUrlCoordinates,
|
||||
private val actualProjectCoordinates: GitLabProjectCoordinates,
|
||||
currentUser: GitLabUserDTO,
|
||||
private val mergeRequest: GitLabMergeRequest,
|
||||
private val discussionsVms: GitLabMergeRequestDiscussionsViewModels,
|
||||
@@ -88,6 +91,8 @@ class GitLabMergeRequestEditorReviewViewModel internal constructor(
|
||||
), CodeReviewInEditorViewModel {
|
||||
private val preferences = project.service<GitLabMergeRequestsPreferences>()
|
||||
|
||||
private val gitRepository: GitRepository = gitRemote.repository
|
||||
|
||||
val mergeRequestIid: String = mergeRequest.iid
|
||||
|
||||
private val _actualChangesState = MutableStateFlow<ChangesState>(ChangesState.NotLoaded)
|
||||
@@ -138,7 +143,7 @@ class GitLabMergeRequestEditorReviewViewModel internal constructor(
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val localRepositorySyncStatus: StateFlow<ComputedResult<GitBranchSyncStatus?>?> by lazy {
|
||||
val repository = projectMapping.remote.repository
|
||||
val repository = gitRepository
|
||||
_actualChangesState.map {
|
||||
(it as? ChangesState.Loaded)?.changes?.commits?.map { it.sha }
|
||||
}.distinctUntilChanged().transformLatest {
|
||||
@@ -188,7 +193,7 @@ class GitLabMergeRequestEditorReviewViewModel internal constructor(
|
||||
override fun updateBranch() {
|
||||
cs.launch {
|
||||
val details = mergeRequest.refreshDataNow()
|
||||
GitLabMergeRequestBranchUtil.fetchAndCheckoutBranch(projectMapping, details)
|
||||
GitLabMergeRequestBranchUtil.fetchAndCheckoutBranch(gitRepository, actualProjectCoordinates.serverPath, details)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +243,7 @@ class GitLabMergeRequestEditorReviewViewModel internal constructor(
|
||||
*/
|
||||
fun getFileStateFlow(virtualFile: VirtualFile): Flow<FileReviewState> {
|
||||
if (!virtualFile.isValid || virtualFile.isDirectory ||
|
||||
!VfsUtilCore.isAncestor(projectMapping.remote.repository.root, virtualFile, true)) {
|
||||
!VfsUtilCore.isAncestor(gitRepository.root, virtualFile, true)) {
|
||||
return flowOf(FileReviewState.NotInReview)
|
||||
}
|
||||
val filePath = VcsContextFactory.getInstance().createFilePathOn(virtualFile)
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ class GitLabMergeRequestTimelineDiscussionViewModelImpl(
|
||||
.modelFlow(cs, LOG)
|
||||
|
||||
override val id: String = discussion.id.toString()
|
||||
override val serverUrl: URL = mr.glProject.serverPath.toURL()
|
||||
override val serverUrl: URL = mr.serverPath.toURL()
|
||||
override val author: Flow<GitLabUserDTO> = mainNote.map { it.author }
|
||||
|
||||
private val _repliesFolded = MutableStateFlow(true)
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ sealed interface GitLabMergeRequestTimelineItemViewModel {
|
||||
override val author: GitLabUserDTO = note.author
|
||||
override val createdAt: Date? = note.createdAt
|
||||
override val isDraft: Boolean = note is GitLabMergeRequestDraftNote
|
||||
override val serverUrl: URL = mr.glProject.serverPath.toURL()
|
||||
override val serverUrl: URL = mr.serverPath.toURL()
|
||||
|
||||
override val actionsVm: GitLabNoteAdminActionsViewModel? =
|
||||
if (note is MutableGitLabNote && note.canAdmin) GitLabNoteAdminActionsViewModelImpl(cs, project, projectData, note) else null
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ internal class LoadAllGitLabMergeRequestTimelineViewModel(
|
||||
null
|
||||
}
|
||||
|
||||
override val serverUrl: URL = mergeRequest.glProject.serverPath.toURL()
|
||||
override val serverUrl: URL = mergeRequest.serverPath.toURL()
|
||||
|
||||
private val _diffRequests = MutableSharedFlow<ChangesSelection.Precise>()
|
||||
val diffRequests: Flow<ChangesSelection.Precise> = _diffRequests.asSharedFlow()
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ internal sealed interface GitLabReviewTabViewModel : ReviewTabViewModel {
|
||||
) : GitLabReviewTabViewModel, Disposable {
|
||||
private val cs = parentCs.childScope(this::class).cancelledWith(this)
|
||||
|
||||
private val projectPath = projectData.projectMapping.repository.projectPath.fullPath()
|
||||
private val projectPath = projectData.projectCoordinates.projectPath
|
||||
override val displayName: String = GitLabBundle.message("merge.request.create.tab.title", projectPath)
|
||||
|
||||
val createVm = GitLabMergeRequestCreateViewModelImpl(
|
||||
|
||||
+33
-16
@@ -3,50 +3,67 @@ package org.jetbrains.plugins.gitlab.mergerequest.util
|
||||
|
||||
import git4idea.GitRemoteBranch
|
||||
import git4idea.remote.hosting.GitRemoteBranchesUtil
|
||||
import git4idea.repo.GitRepository
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerPath
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequestFullDetails
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.getSourceRemoteDescriptor
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.getSpecialRemoteBranchForHead
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.getTargetRemoteDescriptor
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.data.isFork
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
|
||||
object GitLabMergeRequestBranchUtil {
|
||||
private const val FORK_BRANCH_PREFIX = "fork"
|
||||
|
||||
private suspend fun findSourceRemoteBranch(mapping: GitLabProjectMapping, details: GitLabMergeRequestFullDetails): GitRemoteBranch? {
|
||||
val sourceRemoteDescriptor = details.getSourceRemoteDescriptor(mapping.repository.serverPath)
|
||||
private suspend fun findSourceRemoteBranch(
|
||||
gitRepository: GitRepository,
|
||||
serverPath: GitLabServerPath,
|
||||
details: GitLabMergeRequestFullDetails
|
||||
): GitRemoteBranch? {
|
||||
val sourceRemoteDescriptor = details.getSourceRemoteDescriptor(serverPath)
|
||||
|
||||
if (sourceRemoteDescriptor != null) {
|
||||
// Public fork / regular branch
|
||||
return GitRemoteBranchesUtil.findOrCreateRemoteBranch(mapping.gitRepository, sourceRemoteDescriptor, details.sourceBranch)
|
||||
return GitRemoteBranchesUtil.findOrCreateRemoteBranch(gitRepository, sourceRemoteDescriptor, details.sourceBranch)
|
||||
} else {
|
||||
// Private/deleted fork, can still fetch using special MR head ref
|
||||
val targetRemoteDescriptor = details.getTargetRemoteDescriptor(mapping.repository.serverPath)
|
||||
val targetRemote = GitRemoteBranchesUtil.findOrCreateRemote(mapping.gitRepository, targetRemoteDescriptor) ?: return null
|
||||
val targetRemoteDescriptor = details.getTargetRemoteDescriptor(serverPath)
|
||||
val targetRemote = GitRemoteBranchesUtil.findOrCreateRemote(gitRepository, targetRemoteDescriptor) ?: return null
|
||||
return details.getSpecialRemoteBranchForHead(targetRemote)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun findTargetRemoteBranch(mapping: GitLabProjectMapping, details: GitLabMergeRequestFullDetails): GitRemoteBranch? {
|
||||
val targetRemoteDescriptor = details.getTargetRemoteDescriptor(mapping.repository.serverPath)
|
||||
private suspend fun findTargetRemoteBranch(
|
||||
gitRepository: GitRepository,
|
||||
serverPath: GitLabServerPath,
|
||||
details: GitLabMergeRequestFullDetails
|
||||
): GitRemoteBranch? {
|
||||
val targetRemoteDescriptor = details.getTargetRemoteDescriptor(serverPath)
|
||||
|
||||
return GitRemoteBranchesUtil.findOrCreateRemoteBranch(mapping.gitRepository, targetRemoteDescriptor, details.targetBranch)
|
||||
return GitRemoteBranchesUtil.findOrCreateRemoteBranch(gitRepository, targetRemoteDescriptor, details.targetBranch)
|
||||
}
|
||||
|
||||
suspend fun fetchAndCheckoutBranch(mapping: GitLabProjectMapping, details: GitLabMergeRequestFullDetails) {
|
||||
suspend fun fetchAndCheckoutBranch(
|
||||
gitRepository: GitRepository,
|
||||
serverPath: GitLabServerPath,
|
||||
details: GitLabMergeRequestFullDetails
|
||||
) {
|
||||
val localPrefix = if (details.isFork()) {
|
||||
if (details.sourceProject != null) "${FORK_BRANCH_PREFIX}/${details.sourceProject.ownerPath}"
|
||||
else "${FORK_BRANCH_PREFIX}/${details.author.username}"
|
||||
} else null
|
||||
|
||||
val remoteBranch = findSourceRemoteBranch(mapping, details) ?: return
|
||||
GitRemoteBranchesUtil.fetchAndCheckoutRemoteBranch(mapping.gitRepository, remoteBranch, localPrefix)
|
||||
val remoteBranch = findSourceRemoteBranch(gitRepository, serverPath, details) ?: return
|
||||
GitRemoteBranchesUtil.fetchAndCheckoutRemoteBranch(gitRepository, remoteBranch, localPrefix)
|
||||
}
|
||||
|
||||
suspend fun fetchAndShowRemoteBranchInLog(mapping: GitLabProjectMapping, details: GitLabMergeRequestFullDetails) {
|
||||
val sourceRemoteBranch = findSourceRemoteBranch(mapping, details) ?: return
|
||||
val targetRemoteBranch = findTargetRemoteBranch(mapping, details)
|
||||
suspend fun fetchAndShowRemoteBranchInLog(
|
||||
gitRepository: GitRepository,
|
||||
serverPath: GitLabServerPath,
|
||||
details: GitLabMergeRequestFullDetails
|
||||
) {
|
||||
val sourceRemoteBranch = findSourceRemoteBranch(gitRepository, serverPath, details) ?: return
|
||||
val targetRemoteBranch = findTargetRemoteBranch(gitRepository, serverPath, details)
|
||||
|
||||
GitRemoteBranchesUtil.fetchAndShowRemoteBranchInLog(mapping.gitRepository, sourceRemoteBranch, targetRemoteBranch)
|
||||
GitRemoteBranchesUtil.fetchAndShowRemoteBranchInLog(gitRepository, sourceRemoteBranch, targetRemoteBranch)
|
||||
}
|
||||
}
|
||||
+57
-42
@@ -22,7 +22,6 @@ import org.jetbrains.plugins.gitlab.GitLabProjectsManager
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApiManager
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectConnectionManager
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.request.findProject
|
||||
import org.jetbrains.plugins.gitlab.authentication.accounts.GitLabAccount
|
||||
import org.jetbrains.plugins.gitlab.authentication.accounts.GitLabAccountManager
|
||||
@@ -34,6 +33,7 @@ import org.jetbrains.plugins.gitlab.mergerequest.data.GitLabMergeRequestState
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.ui.create.action.GitLabMergeRequestOpenCreateTabNotificationAction
|
||||
import org.jetbrains.plugins.gitlab.mergerequest.ui.create.action.GitLabOpenMergeRequestExistingTabNotificationAction
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectMapping
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
|
||||
private val LOG = logger<GitLabPushNotificationCustomizer>()
|
||||
|
||||
@@ -48,31 +48,53 @@ internal class GitLabPushNotificationCustomizer(private val project: Project) :
|
||||
|
||||
// If we already have a GitLab connection open, make sure it matches
|
||||
val connection = project.serviceAsync<GitLabProjectConnectionManager>().connectionState.value
|
||||
if (connection != null && (connection.repo.gitRepository != repository || connection.repo.gitRemote != remoteBranch.remote)) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val (projectMapping, account) = connection?.let {
|
||||
it.repo to it.account
|
||||
} ?: run {
|
||||
val accountManager = serviceAsync<GitLabAccountManager>()
|
||||
val savedAccount = project.serviceAsync<GitLabMergeRequestsPreferences>().selectedUrlAndAccountId?.second?.let { savedId ->
|
||||
accountManager.findAccountOrNull { it.id == savedId }
|
||||
if (connection != null) {
|
||||
if (connection.repo.gitRepository != repository || connection.repo.gitRemote != remoteBranch.remote) {
|
||||
return emptyList()
|
||||
}
|
||||
GitPushNotificationUtil.findRepositoryAndAccount(
|
||||
project.serviceAsync<GitLabProjectsManager>().knownRepositories,
|
||||
repository, remoteBranch.remote,
|
||||
accountManager.accountsState.value,
|
||||
savedAccount,
|
||||
project.serviceAsync<GitLabProjectDefaultAccountHolder>().account
|
||||
)
|
||||
} ?: return emptyList()
|
||||
return createActionList(connection.account, connection.projectData.projectCoordinates.projectPath, remoteBranch, connection.repo)
|
||||
}
|
||||
|
||||
if (!canCreateReview(projectMapping, account, remoteBranch)) {
|
||||
val accountManager = serviceAsync<GitLabAccountManager>()
|
||||
val savedAccount = project.serviceAsync<GitLabMergeRequestsPreferences>().selectedUrlAndAccountId?.second?.let { savedId ->
|
||||
accountManager.findAccountOrNull { it.id == savedId }
|
||||
}
|
||||
val (projectMapping, account) = GitPushNotificationUtil.findRepositoryAndAccount(
|
||||
project.serviceAsync<GitLabProjectsManager>().knownRepositories,
|
||||
repository, remoteBranch.remote,
|
||||
accountManager.accountsState.value,
|
||||
savedAccount,
|
||||
project.serviceAsync<GitLabProjectDefaultAccountHolder>().account
|
||||
) ?: return emptyList()
|
||||
// be aware, for a renamed project no action will be returned, because of the incorrect path
|
||||
val projectFullPath = projectMapping.repository.projectPath
|
||||
return createActionList(account, projectFullPath, remoteBranch, projectMapping)
|
||||
}
|
||||
|
||||
private suspend fun createActionList(
|
||||
account: GitLabAccount,
|
||||
projectFullPath: GitLabProjectPath,
|
||||
remoteBranch: GitRemoteBranch,
|
||||
projectMapping: GitLabProjectMapping,
|
||||
): List<AnAction> {
|
||||
val accountManager = serviceAsync<GitLabAccountManager>()
|
||||
val token = accountManager.findCredentials(account) ?: return emptyList()
|
||||
val api = serviceAsync<GitLabApiManager>().getClient(account.server, token)
|
||||
|
||||
if (!canCreateReview(api, projectFullPath, remoteBranch)) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val existingMRs = findExistingMergeRequests(projectMapping, account, remoteBranch)
|
||||
val existingMRs = findExistingMergeRequests(api, projectFullPath, remoteBranch)
|
||||
return actions(existingMRs, projectMapping, account)
|
||||
}
|
||||
|
||||
private fun actions(
|
||||
existingMRs: List<GitLabMergeRequestByBranchDTO>,
|
||||
projectMapping: GitLabProjectMapping,
|
||||
account: GitLabAccount,
|
||||
): List<AnAction> {
|
||||
return when (existingMRs.size) {
|
||||
0 -> {
|
||||
listOf(GitLabMergeRequestOpenCreateTabNotificationAction(project, projectMapping, account))
|
||||
@@ -93,14 +115,13 @@ internal class GitLabPushNotificationCustomizer(private val project: Project) :
|
||||
* - The repository must exist
|
||||
* - The branch cannot be the default branch (we don't allow creating an MR from default -> default)
|
||||
*/
|
||||
private suspend fun canCreateReview(projectMapping: GitLabProjectMapping, account: GitLabAccount, branch: GitRemoteBranch): Boolean {
|
||||
val accountManager = serviceAsync<GitLabAccountManager>()
|
||||
val token = accountManager.findCredentials(account) ?: return false
|
||||
val api = serviceAsync<GitLabApiManager>().getClient(account.server, token)
|
||||
|
||||
val repository = projectMapping.repository
|
||||
val repositoryInfo = getRepositoryInfo(api, repository) ?: run {
|
||||
LOG.warn("Repository not found: $repository")
|
||||
private suspend fun canCreateReview(
|
||||
api: GitLabApi,
|
||||
projectFullPath: GitLabProjectPath,
|
||||
branch: GitRemoteBranch,
|
||||
): Boolean {
|
||||
val repositoryInfo = getRepositoryInfo(api, projectFullPath) ?: run {
|
||||
LOG.warn("Repository not found: $projectFullPath")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -109,15 +130,15 @@ internal class GitLabPushNotificationCustomizer(private val project: Project) :
|
||||
return repositoryInfo.rootRef != remoteBranchName
|
||||
}
|
||||
|
||||
private suspend fun getRepositoryInfo(api: GitLabApi, project: GitLabProjectCoordinates) =
|
||||
private suspend fun getRepositoryInfo(api: GitLabApi, projectFullPath: GitLabProjectPath) =
|
||||
try {
|
||||
api.graphQL.findProject(project).body()?.repository
|
||||
api.graphQL.findProject(projectFullPath).body()?.repository
|
||||
}
|
||||
catch (ce: CancellationException) {
|
||||
throw ce
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn("Failed to lookup repository $project", e)
|
||||
LOG.warn("Failed to lookup repository $projectFullPath in $project", e)
|
||||
null
|
||||
}
|
||||
|
||||
@@ -125,28 +146,22 @@ internal class GitLabPushNotificationCustomizer(private val project: Project) :
|
||||
* Look up any existing open merge requests on the given remote branch.
|
||||
*/
|
||||
private suspend fun findExistingMergeRequests(
|
||||
projectMapping: GitLabProjectMapping,
|
||||
account: GitLabAccount,
|
||||
api: GitLabApi,
|
||||
targetProjectPath: GitLabProjectPath,
|
||||
branch: GitRemoteBranch,
|
||||
): List<GitLabMergeRequestByBranchDTO> {
|
||||
val accountManager = serviceAsync<GitLabAccountManager>()
|
||||
val token = accountManager.findCredentials(account) ?: return emptyList()
|
||||
val api = serviceAsync<GitLabApiManager>().getClient(account.server, token)
|
||||
|
||||
val repository = projectMapping.repository
|
||||
val remoteBranchName = branch.nameForRemoteOperations
|
||||
|
||||
return withContext(Dispatchers.IO) {
|
||||
val targetProjectPath = repository.projectPath.fullPath()
|
||||
try {
|
||||
val mrs = api.graphQL.findMergeRequestsByBranch(repository, GitLabMergeRequestState.OPENED, remoteBranchName).body()!!.nodes
|
||||
mrs.filter { it.targetProject.fullPath == targetProjectPath && it.sourceProject?.fullPath == targetProjectPath }
|
||||
val mrs = api.graphQL.findMergeRequestsByBranch(targetProjectPath, GitLabMergeRequestState.OPENED, remoteBranchName).body()!!.nodes
|
||||
mrs.filter { it.targetProject.fullPath == targetProjectPath.fullPath() && it.sourceProject?.fullPath == targetProjectPath.fullPath() }
|
||||
}
|
||||
catch (ce: CancellationException) {
|
||||
throw ce
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn("Failed to lookup existing merge requests for branch $remoteBranchName in $repository", e)
|
||||
LOG.warn("Failed to lookup existing merge requests for branch $remoteBranchName in $targetProjectPath", e)
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
+7
-8
@@ -44,9 +44,8 @@ import org.intellij.markdown.parser.sequentialparsers.impl.MathParser
|
||||
import org.intellij.markdown.parser.sequentialparsers.impl.ReferenceLinkParser
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabId
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerPath
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUri
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
import java.net.URI
|
||||
import java.nio.file.InvalidPathException
|
||||
@@ -59,8 +58,9 @@ import java.nio.file.InvalidPathException
|
||||
class GitLabMarkdownToHtmlConverter(
|
||||
private val project: Project,
|
||||
private val repository: GitRepository,
|
||||
projectCoordinates: GitLabProjectCoordinates,
|
||||
projectId: GitLabId,
|
||||
serverPath: GitLabServerPath,
|
||||
projectId: String,
|
||||
private val projectPath: GitLabProjectPath,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -70,9 +70,8 @@ class GitLabMarkdownToHtmlConverter(
|
||||
internal const val OPEN_MR_LINK_PREFIX = "glmergerequest:"
|
||||
}
|
||||
|
||||
private val projectWebUrlBase: String = projectCoordinates.serverPath.toString() + "/-/project/" + projectId.guessRestId()
|
||||
private val projectApiUri: URI = projectCoordinates.restApiUri
|
||||
private val projectPath: GitLabProjectPath = projectCoordinates.projectPath
|
||||
private val projectWebUrlBase: String = "$serverPath/-/project/$projectId"
|
||||
private val projectApiUri: URI = serverPath.projectApiUri(projectId)
|
||||
|
||||
/**
|
||||
* Makes file links relative to the git repository root or to the external root.
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ class GitLabMergeRequestStandaloneDraftNoteViewModelBase internal constructor(
|
||||
override val author: GitLabUserDTO = note.author
|
||||
override val createdAt: Date? = note.createdAt
|
||||
override val isDraft: Boolean = true
|
||||
override val serverUrl: URL = mr.glProject.serverPath.toURL()
|
||||
override val serverUrl: URL = mr.serverPath.toURL()
|
||||
|
||||
override val actionsVm: GitLabNoteAdminActionsViewModel? =
|
||||
if (note.canAdmin) GitLabNoteAdminActionsViewModelImpl(cs, project, projectData, note) else null
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ class GitLabNoteViewModelImpl(
|
||||
override val author: GitLabUserDTO = note.author
|
||||
override val createdAt: Date? = note.createdAt
|
||||
override val isDraft: Boolean = note is GitLabMergeRequestDraftNote
|
||||
override val serverUrl: URL = projectData.projectMapping.repository.serverPath.toURL()
|
||||
override val serverUrl: URL = projectData.projectCoordinates.serverPath.toURL()
|
||||
|
||||
override val actionsVm: GitLabNoteAdminActionsViewModel? =
|
||||
if (note is MutableGitLabNote && note.canAdmin) GitLabNoteAdminActionsViewModelImpl(cs, project, projectData, note) else null
|
||||
|
||||
+6
-7
@@ -4,10 +4,9 @@ package org.jetbrains.plugins.gitlab.upload
|
||||
import com.intellij.collaboration.api.json.loadJsonValue
|
||||
import com.intellij.collaboration.util.resolveRelative
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.SinceGitLab
|
||||
import org.jetbrains.plugins.gitlab.api.dto.GitLabUploadRestDTO
|
||||
import org.jetbrains.plugins.gitlab.api.restApiUri
|
||||
import org.jetbrains.plugins.gitlab.api.projectApiUrl
|
||||
import java.io.InputStream
|
||||
import java.net.http.HttpRequest.BodyPublishers
|
||||
import java.net.http.HttpResponse
|
||||
@@ -16,10 +15,10 @@ import java.util.UUID
|
||||
|
||||
@SinceGitLab("15.10")
|
||||
internal suspend fun GitLabApi.Rest.markdownUploadFile(
|
||||
project: GitLabProjectCoordinates,
|
||||
filename: String,
|
||||
mimeType: String,
|
||||
fileInputStream: InputStream,
|
||||
projectId: String,
|
||||
filename: String,
|
||||
mimeType: String,
|
||||
fileInputStream: InputStream,
|
||||
): HttpResponse<out GitLabUploadRestDTO> {
|
||||
val boundary = "FormBoundary" + UUID.randomUUID()
|
||||
val boundaryStart = "--$boundary\r\n" +
|
||||
@@ -33,7 +32,7 @@ internal suspend fun GitLabApi.Rest.markdownUploadFile(
|
||||
BodyPublishers.ofString(boundaryEnd)
|
||||
)
|
||||
|
||||
val uri = project.restApiUri.resolveRelative("uploads")
|
||||
val uri = projectApiUrl(projectId).resolveRelative("uploads")
|
||||
val httpRequest = request(uri)
|
||||
.POST(bodyPublisher)
|
||||
.header("Content-Type", "multipart/form-data; boundary=$boundary")
|
||||
|
||||
+6
-3
@@ -3,7 +3,6 @@ package org.jetbrains.plugins.gitlab.util
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.util.text.nullize
|
||||
import git4idea.remote.GitRemoteUrlCoordinates
|
||||
import git4idea.remote.hosting.GitHostingUrlUtil
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerPath
|
||||
@@ -17,13 +16,17 @@ data class GitLabProjectPath(val owner: @NlsSafe String, val name: @NlsSafe Stri
|
||||
override fun toString(): String = "$owner/$name"
|
||||
|
||||
companion object {
|
||||
fun create(server: GitLabServerPath, remote: GitRemoteUrlCoordinates): GitLabProjectPath? {
|
||||
fun create(server: GitLabServerPath, gitRemoteUrl: String): GitLabProjectPath? {
|
||||
val serverPath = server.toURI().path
|
||||
val remotePath = GitHostingUrlUtil.getUriFromRemoteUrl(remote.url)?.path ?: return null
|
||||
val remotePath = GitHostingUrlUtil.getUriFromRemoteUrl(gitRemoteUrl)?.path ?: return null
|
||||
|
||||
if (!remotePath.startsWith(serverPath)) return null
|
||||
val repositoryPath = remotePath.removePrefix(serverPath).removePrefix("/")
|
||||
|
||||
return extractProjectPath(repositoryPath)
|
||||
}
|
||||
|
||||
fun extractProjectPath(repositoryPath: String): GitLabProjectPath? {
|
||||
val lastSlashIdx = repositoryPath.lastIndexOf('/')
|
||||
if (lastSlashIdx < 0) return null
|
||||
|
||||
|
||||
+4
-3
@@ -96,7 +96,7 @@ object GitLabStatistics {
|
||||
//endregion
|
||||
|
||||
//region Counters
|
||||
private val COUNTERS_GROUP = EventLogGroup("vcs.gitlab.counters", version = 30)
|
||||
private val COUNTERS_GROUP = EventLogGroup("vcs.gitlab.counters", version = 31)
|
||||
|
||||
/**
|
||||
* Server metadata was fetched
|
||||
@@ -333,6 +333,7 @@ object GitLabStatistics {
|
||||
|
||||
enum class GitLabApiRequestName {
|
||||
REST_GET_CURRENT_USER,
|
||||
REST_GET_PROJECT,
|
||||
REST_GET_PROJECT_IS_FORKED,
|
||||
REST_GET_PROJECT_NAMESPACE,
|
||||
REST_GET_PROJECT_USERS,
|
||||
@@ -446,7 +447,7 @@ internal class GitLabMetricsLoader(private val project: Project) {
|
||||
val nonFork = withContext(Dispatchers.IO) {
|
||||
knownRepos.firstOrNull { repo ->
|
||||
val (api, _) = getApi(repo.repository.serverPath) ?: return@firstOrNull false
|
||||
!api.isProjectForked(repo.repository)
|
||||
!api.isProjectForked(repo.repository.projectPath)
|
||||
}
|
||||
}
|
||||
if (nonFork != null) return nonFork
|
||||
@@ -460,7 +461,7 @@ internal class GitLabMetricsLoader(private val project: Project) {
|
||||
val chosenRepoMapping = chooseRepo() ?: return null
|
||||
|
||||
val (api, account) = getApi(chosenRepoMapping.repository.serverPath) ?: return null
|
||||
return api.graphQL.getMergeRequestMetrics(chosenRepoMapping.repository, account.name).body()
|
||||
return api.graphQL.getMergeRequestMetrics(chosenRepoMapping.repository.projectPath, account.name).body()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn("Failed to load metrics", e)
|
||||
|
||||
+6
-9
@@ -7,16 +7,14 @@ import git4idea.repo.GitRepository
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabRestIdData
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabServerPath
|
||||
import org.jetbrains.plugins.gitlab.ui.GitLabMarkdownToHtmlConverter.Companion.OPEN_FILE_LINK_PREFIX
|
||||
import org.jetbrains.plugins.gitlab.ui.GitLabMarkdownToHtmlConverter.Companion.OPEN_MR_LINK_PREFIX
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath
|
||||
import org.jetbrains.plugins.gitlab.util.GitLabProjectPath.Companion.extractProjectPath
|
||||
import java.nio.file.Path
|
||||
|
||||
private const val IMAGES_API_BASE = """http://base/url/api/v4/projects/test-account%2Fmr-test"""
|
||||
private const val WEB_BASE = """http://base/url/-/project/testRestId"""
|
||||
private const val IMAGES_API_BASE = """http://base/url/api/v4/projects/1"""
|
||||
private const val WEB_BASE = """http://base/url/-/project/1"""
|
||||
private const val P_CLASS = """class="custom_image""""
|
||||
|
||||
class GitLabMarkdownToHtmlConverterTest : LightPlatformTestCase() {
|
||||
@@ -318,10 +316,9 @@ class GitLabMarkdownToHtmlConverterTest : LightPlatformTestCase() {
|
||||
|
||||
private fun convertToHtml(markdownSource: String): @NlsSafe String {
|
||||
val serverPath = GitLabServerPath("http://base/url")
|
||||
val projectPath = GitLabProjectPath("test-account", "mr-test")
|
||||
val projectCoordinates = GitLabProjectCoordinates(serverPath, projectPath)
|
||||
val projectId = GitLabRestIdData("testRestId")
|
||||
val converter = GitLabMarkdownToHtmlConverter(project, gitRepository, projectCoordinates, projectId)
|
||||
val projectId = "1"
|
||||
val projectFullPath = extractProjectPath("test-account/mr-test") ?: error("Failed to extract project path")
|
||||
val converter = GitLabMarkdownToHtmlConverter(project, gitRepository, serverPath, projectId, projectFullPath)
|
||||
return converter.convertToHtml(markdownSource)
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gitlab.util
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class GitLabProjectPathTest {
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with valid path`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("owner/project")
|
||||
assertThat(result).isNotNull
|
||||
assertThat(result?.owner).isEqualTo("owner")
|
||||
assertThat(result?.name).isEqualTo("project")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with nested owner path`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("group/subgroup/project")
|
||||
assertThat(result).isNotNull
|
||||
assertThat(result?.owner).isEqualTo("group/subgroup")
|
||||
assertThat(result?.name).isEqualTo("project")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with deeply nested path`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("org/team/subteam/project")
|
||||
assertThat(result).isNotNull
|
||||
assertThat(result?.owner).isEqualTo("org/team/subteam")
|
||||
assertThat(result?.name).isEqualTo("project")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with no slash returns null`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("project")
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with empty string returns null`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("")
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with only slash returns null`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("/")
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with trailing slash returns null`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("owner/project/")
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with leading slash`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("/owner/project")
|
||||
assertThat(result).isNotNull
|
||||
assertThat(result?.owner).isEqualTo("/owner")
|
||||
assertThat(result?.name).isEqualTo("project")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with empty owner returns null`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("/project")
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with whitespace in path`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("owner with spaces/project name")
|
||||
assertThat(result).isNotNull
|
||||
assertThat(result?.owner).isEqualTo("owner with spaces")
|
||||
assertThat(result?.name).isEqualTo("project name")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extractProjectPath with special characters`() {
|
||||
val result = GitLabProjectPath.extractProjectPath("owner-name/project.name")
|
||||
assertThat(result).isNotNull
|
||||
assertThat(result?.owner).isEqualTo("owner-name")
|
||||
assertThat(result?.name).isEqualTo("project.name")
|
||||
}
|
||||
}
|
||||
+41
-37
@@ -81,7 +81,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(9, 0)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val commits = api.rest.loadMergeRequestCommits(api.getMergeRequestCommitsURI(glTest1Coordinates, "2")).body()
|
||||
val commits = api.rest.loadMergeRequestCommits(api.rest.getMergeRequestCommitsURI(glTest1ProjectId, "2")).body()
|
||||
|
||||
assertIterableEquals(glTest1Mr2CommitShortShas, commits.map { it.shortId })
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(inRange(v(9, 0), v(15, 7)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val changes = api.rest.loadMergeRequestChanges(api.getMergeRequestChangesURI(glTest1Coordinates, "2")).body()
|
||||
val changes = api.rest.loadMergeRequestChanges(api.rest.getMergeRequestChangesURI(glTest1ProjectId, "2")).body()
|
||||
|
||||
assertIterableEquals(glTest1Mr2ChangedFiles, changes.changes.map { it.newPath })
|
||||
}
|
||||
@@ -103,7 +103,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(15, 7)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val diffs = api.rest.loadMergeRequestDiffs(api.getMergeRequestDiffsURI(glTest1Coordinates, "2", 1)).body()
|
||||
val diffs = api.rest.loadMergeRequestDiffs(api.rest.getMergeRequestDiffsURI(glTest1ProjectId, "2", 1)).body()
|
||||
|
||||
assertIterableEquals(glTest1Mr2ChangedFiles, diffs.map { it.newPath })
|
||||
}
|
||||
@@ -114,7 +114,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(7, 0)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val diffs = api.rest.loadCommitDiffs(getCommitDiffsURI(glTest1Coordinates, glTest1Mr2CommitShortShas[0])).body()
|
||||
val diffs = api.rest.loadCommitDiffs(api.rest.getCommitDiffsURI(glTest1ProjectId, glTest1Mr2CommitShortShas[0])).body()
|
||||
|
||||
assertIterableEquals(glTest1Mr2ChangedFiles, diffs.map { it.newPath })
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(7, 0)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val commit = api.rest.loadCommit(glTest1Coordinates, glTest1Mr2CommitShortShas[0]).body()
|
||||
val commit = api.rest.loadCommit(glTest1ProjectId, glTest1Mr2CommitShortShas[0]).body()
|
||||
|
||||
assertEquals(glTest1Mr2CommitShas[0], commit.id)
|
||||
}
|
||||
@@ -136,7 +136,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(10, 6)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val uri = getMergeRequestDiscussionsUri(glTest1Coordinates, "2")
|
||||
val uri = api.rest.getMergeRequestDiscussionsUri(glTest1ProjectId, "2")
|
||||
val discussions = ApiPageUtil.createPagesFlowByLinkHeader(uri) {
|
||||
api.rest.loadUpdatableJsonList<GitLabDiscussionRestDTO>(
|
||||
GitLabApiRequestName.REST_GET_MERGE_REQUEST_DISCUSSIONS, it
|
||||
@@ -160,14 +160,14 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
requiresAuthentication { api ->
|
||||
val randomId = Random.nextLong()
|
||||
val initialBody = "This is a new comment! ID=$randomId"
|
||||
val addNoteResult = api.rest.addNote(volatileProjectCoordinates, volatileProjectMr1Iid, initialBody)
|
||||
val addNoteResult = api.rest.addNote(volatileProjectId, volatileProjectMr1Iid, initialBody)
|
||||
assertNotNull(addNoteResult)
|
||||
val addNoteResultValue = addNoteResult.body()
|
||||
assertNotNull(addNoteResultValue)
|
||||
|
||||
val nextBody = "Changed comment! ID=$randomId"
|
||||
|
||||
val updateNoteResult = api.rest.updateNote(volatileProjectCoordinates,
|
||||
val updateNoteResult = api.rest.updateNote(volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
addNoteResultValue.id.toString(),
|
||||
addNoteResultValue.notes.first().id.toString(),
|
||||
@@ -176,19 +176,19 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
|
||||
// Check body changed
|
||||
// NOTE: WILL NOT WORK ON A CONSTANTLY RUNNING SERVER BECAUSE OF PAGINATION
|
||||
val discussions = api.rest.loadMergeRequestDiscussions(volatileProjectCoordinates, volatileProjectMr1Iid).body()
|
||||
val discussions = api.rest.loadMergeRequestDiscussions(volatileProjectId, volatileProjectMr1Iid).body()
|
||||
val updatedNote = discussions.find { it.id.toString() == addNoteResultValue.id.toString() }
|
||||
assertNotNull(updatedNote)
|
||||
|
||||
assertEquals(nextBody, updatedNote.notes[0].body)
|
||||
|
||||
val deleteNoteResult = api.rest.deleteNote(volatileProjectCoordinates,
|
||||
val deleteNoteResult = api.rest.deleteNote(volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
updatedNote.id.toString(),
|
||||
updatedNote.notes.first().id.toString()).body()
|
||||
assertNotNull(deleteNoteResult)
|
||||
// Check is deleted
|
||||
val deletedNote = api.rest.loadMergeRequestDiscussions(volatileProjectCoordinates, volatileProjectMr1Iid).body()
|
||||
val deletedNote = api.rest.loadMergeRequestDiscussions(volatileProjectId, volatileProjectMr1Iid).body()
|
||||
.find { it.id.toString() == addNoteResultValue.id.toString() }
|
||||
|
||||
assertNull(deletedNote)
|
||||
@@ -203,14 +203,14 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
val randomId = Random.nextLong()
|
||||
val initialBody = "This is a diff note! ID=$randomId"
|
||||
val addNoteResult = api.rest.addDiffNote(
|
||||
volatileProjectCoordinates,
|
||||
volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
GitLabDiffPositionInput("bd857928", "bd857928", 1, "063282e5", 1,
|
||||
DiffPathsInputDTO("README.md", null)),
|
||||
initialBody
|
||||
).body()
|
||||
assertNotNull(addNoteResult)
|
||||
val deleteNoteResult = api.rest.deleteNote(volatileProjectCoordinates,
|
||||
val deleteNoteResult = api.rest.deleteNote(volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
addNoteResult.id.toString(),
|
||||
addNoteResult.notes[0].id.toString()).body()
|
||||
@@ -226,7 +226,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
val randomId = Random.nextLong()
|
||||
val initialBody = "This is a note! ID=$randomId"
|
||||
val addNoteResult = api.rest.addNote(
|
||||
volatileProjectCoordinates,
|
||||
volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
initialBody
|
||||
).body()
|
||||
@@ -234,7 +234,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
|
||||
val replyBody = "This is a reply! ID=$randomId"
|
||||
val addNoteResult2 = api.rest.createReplyNote(
|
||||
volatileProjectCoordinates,
|
||||
volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
addNoteResult.id.toString(),
|
||||
replyBody
|
||||
@@ -242,18 +242,18 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
assertNotNull(addNoteResult2)
|
||||
|
||||
// NOTE: WILL NOT WORK ON A CONSTANTLY RUNNING SERVER BECAUSE OF PAGINATION
|
||||
val result = api.rest.loadMergeRequestDiscussions(volatileProjectCoordinates, volatileProjectMr1Iid).body()
|
||||
val result = api.rest.loadMergeRequestDiscussions(volatileProjectId, volatileProjectMr1Iid).body()
|
||||
assertNotNull(result)
|
||||
|
||||
val discussion = result.find { addNoteResult.notes[0].body.contains(randomId.toString()) }
|
||||
assertNotNull(discussion)
|
||||
|
||||
val deleteNoteResult1 =
|
||||
api.rest.deleteNote(volatileProjectCoordinates, volatileProjectMr1Iid, discussion.id.toString(), discussion.notes[0].id.toString())
|
||||
api.rest.deleteNote(volatileProjectId, volatileProjectMr1Iid, discussion.id.toString(), discussion.notes[0].id.toString())
|
||||
.body()
|
||||
assertNotNull(deleteNoteResult1)
|
||||
val deleteNoteResult2 =
|
||||
api.rest.deleteNote(volatileProjectCoordinates, volatileProjectMr1Iid, discussion.id.toString(), discussion.notes[1].id.toString())
|
||||
api.rest.deleteNote(volatileProjectId, volatileProjectMr1Iid, discussion.id.toString(), discussion.notes[1].id.toString())
|
||||
.body()
|
||||
assertNotNull(deleteNoteResult2)
|
||||
}
|
||||
@@ -267,7 +267,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
val randomId = Random.nextLong()
|
||||
val initialBody = "This is a diff note! ID=$randomId"
|
||||
val addNoteResult = api.rest.addDiffNote(
|
||||
volatileProjectCoordinates,
|
||||
volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
GitLabDiffPositionInput("bd857928", "bd857928", 1, "063282e5", 1,
|
||||
DiffPathsInputDTO("README.md", null)),
|
||||
@@ -277,7 +277,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
|
||||
val replyBody = "This is a reply! ID=$randomId"
|
||||
val addNoteResult2 = api.rest.createReplyNote(
|
||||
volatileProjectCoordinates,
|
||||
volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
addNoteResult.id.toString(),
|
||||
replyBody
|
||||
@@ -285,7 +285,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
assertNotNull(addNoteResult2)
|
||||
|
||||
// NOTE: WILL NOT WORK ON A CONSTANTLY RUNNING SERVER BECAUSE OF PAGINATION
|
||||
val result1 = api.rest.loadMergeRequestDiscussions(volatileProjectCoordinates, volatileProjectMr1Iid).body()
|
||||
val result1 = api.rest.loadMergeRequestDiscussions(volatileProjectId, volatileProjectMr1Iid).body()
|
||||
assertNotNull(result1)
|
||||
|
||||
val discussion1 = result1.find { addNoteResult.notes[0].body.contains(randomId.toString()) }
|
||||
@@ -293,24 +293,24 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
assertFalse(discussion1.notes[0].resolved)
|
||||
|
||||
val resolveNoteResult =
|
||||
api.rest.changeMergeRequestDiscussionResolve(volatileProjectCoordinates, volatileProjectMr1Iid, discussion1.id.toString(), true)
|
||||
api.rest.changeMergeRequestDiscussionResolve(volatileProjectId, volatileProjectMr1Iid, discussion1.id.toString(), true)
|
||||
.body()
|
||||
assertNotNull(resolveNoteResult)
|
||||
|
||||
// Confirm is now resolved
|
||||
val result2 = api.rest.loadMergeRequestDiscussions(volatileProjectCoordinates, volatileProjectMr1Iid).body()
|
||||
val result2 = api.rest.loadMergeRequestDiscussions(volatileProjectId, volatileProjectMr1Iid).body()
|
||||
assertNotNull(result2)
|
||||
|
||||
val discussion2 = result2.find { addNoteResult.notes[0].body.contains(randomId.toString()) }
|
||||
assertNotNull(discussion2)
|
||||
assertTrue(discussion2.notes[0].resolved)
|
||||
|
||||
val deleteNoteResult1 = api.rest.deleteNote(volatileProjectCoordinates,
|
||||
val deleteNoteResult1 = api.rest.deleteNote(volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
discussion2.id.toString(),
|
||||
discussion2.notes[0].id.toString()).body()
|
||||
assertNotNull(deleteNoteResult1)
|
||||
val deleteNoteResult2 = api.rest.deleteNote(volatileProjectCoordinates,
|
||||
val deleteNoteResult2 = api.rest.deleteNote(volatileProjectId,
|
||||
volatileProjectMr1Iid,
|
||||
discussion2.id.toString(),
|
||||
discussion2.notes[1].id.toString()).body()
|
||||
@@ -323,7 +323,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(15, 9)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val uri = getMergeRequestDraftNotesUri(glTest1Coordinates, glTest1Mr2Iid)
|
||||
val uri = api.rest.getMergeRequestDraftNotesUri(glTest1ProjectId, glTest1Mr2Iid)
|
||||
val draftNotes = ApiPageUtil.createPagesFlowByLinkHeader(uri) {
|
||||
api.rest.loadUpdatableJsonList<GitLabMergeRequestDraftNoteRestDTO>(
|
||||
GitLabApiRequestName.REST_GET_DRAFT_NOTES, it
|
||||
@@ -343,7 +343,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
requiresAuthentication { api ->
|
||||
val mrs = api.rest.loadUpdatableJsonList<GitLabMergeRequestShortRestDTO>(
|
||||
GitLabApiRequestName.REST_GET_MERGE_REQUESTS,
|
||||
getMergeRequestListURI(glTest1Coordinates, "search=important")
|
||||
api.rest.getMergeRequestListURI(glTest1ProjectId, "search=important")
|
||||
).body()
|
||||
|
||||
assertNotNull(mrs)
|
||||
@@ -356,7 +356,8 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(12, 0)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val mr = api.graphQL.loadMergeRequest(glTest1Coordinates, "2").body()
|
||||
val testProject1 = glTest1Coordinates
|
||||
val mr = api.graphQL.loadMergeRequest(testProject1.projectPath, "2").body()
|
||||
|
||||
assertNotNull(mr)
|
||||
assertEquals("2", mr.iid)
|
||||
@@ -368,7 +369,8 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(13, 1)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val mrs = api.graphQL.findMergeRequestsByBranch(glTest1Coordinates, GitLabMergeRequestState.ALL, "changes-on-b").body()
|
||||
val testProject1 = glTest1Coordinates
|
||||
val mrs = api.graphQL.findMergeRequestsByBranch(testProject1.projectPath, GitLabMergeRequestState.ALL, "changes-on-b").body()
|
||||
|
||||
assertNotNull(mrs)
|
||||
assertEquals(listOf("3"), mrs.nodes.map { it.iid })
|
||||
@@ -382,7 +384,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
requiresAuthentication { api ->
|
||||
val reloadRequest = MutableSharedFlow<Unit>(1).withInitial(Unit)
|
||||
val loader = startGitLabRestETagListLoaderIn(backgroundScope,
|
||||
getMergeRequestStateEventsUri(glTest1Coordinates, "1"),
|
||||
api.rest.getMergeRequestStateEventsUri(glTest1ProjectId, "1"),
|
||||
{ it.id },
|
||||
reloadRequest,
|
||||
shouldTryToLoadAll = false) { uri, eTag ->
|
||||
@@ -404,7 +406,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
requiresAuthentication { api ->
|
||||
val reloadRequest = MutableSharedFlow<Unit>(1).withInitial(Unit)
|
||||
val loader = startGitLabRestETagListLoaderIn(backgroundScope,
|
||||
getMergeRequestLabelEventsUri(glTest1Coordinates, "1"),
|
||||
api.rest.getMergeRequestLabelEventsUri(glTest1ProjectId, "1"),
|
||||
{ it.id },
|
||||
reloadRequest,
|
||||
shouldTryToLoadAll = false) { uri, eTag ->
|
||||
@@ -426,7 +428,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
requiresAuthentication { api ->
|
||||
val reloadRequest = MutableSharedFlow<Unit>(1).withInitial(Unit)
|
||||
val loader = startGitLabRestETagListLoaderIn(backgroundScope,
|
||||
getMergeRequestMilestoneEventsUri(glTest1Coordinates, "1"),
|
||||
api.rest.getMergeRequestMilestoneEventsUri(glTest1ProjectId, "1"),
|
||||
{ it.id },
|
||||
reloadRequest,
|
||||
shouldTryToLoadAll = false) { uri, eTag ->
|
||||
@@ -449,8 +451,8 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
}
|
||||
|
||||
requiresAuthentication { api ->
|
||||
api.rest.mergeRequestApprove(volatileProjectCoordinates, volatileProjectMr2Iid).body()
|
||||
api.rest.mergeRequestUnApprove(volatileProjectCoordinates, volatileProjectMr2Iid).body()
|
||||
api.rest.mergeRequestApprove(volatileProjectId, volatileProjectMr2Iid).body()
|
||||
api.rest.mergeRequestUnApprove(volatileProjectId, volatileProjectMr2Iid).body()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +461,8 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(13, 1)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val flow = api.graphQL.createAllProjectLabelsFlow(glTests2Coordinates)
|
||||
val glTests2Project = glTests2Coordinates.projectPath
|
||||
val flow = api.graphQL.createAllProjectLabelsFlow(glTests2Project)
|
||||
val labels = flow.foldToList().sortedBy { it.title }
|
||||
|
||||
assertIterableEquals(listOf(testsGroupLabel1, testsGroupLabel2, glTests2Label1, glTests2Label2), labels)
|
||||
@@ -471,7 +474,7 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
checkVersion(after(v(9, 0)))
|
||||
|
||||
requiresAuthentication { api ->
|
||||
val users = api.rest.getProjectUsers(getProjectUsersURI(glTests2Coordinates)).body()
|
||||
val users = api.rest.getProjectUsers(api.rest.getProjectUsersURI(glTests2ProjectId)).body()
|
||||
|
||||
assertTrue(users.map { it.username }.contains(rootUsername))
|
||||
}
|
||||
@@ -560,7 +563,8 @@ class GitLabApiTest : GitLabApiTestCase() {
|
||||
assertNotNull(it, "test-png.png resource should exist")
|
||||
val name = "test-image"
|
||||
val filename = "$name.png"
|
||||
val uploadResult = api.rest.markdownUploadFile(glTest1Coordinates, filename, "image/png", it).body()
|
||||
|
||||
val uploadResult = api.rest.markdownUploadFile(glTest1ProjectId, filename, "image/png", it).body()
|
||||
assertNotNull(uploadResult)
|
||||
val markdown = uploadResult.markdown
|
||||
assertTrue(markdown.startsWith(",
|
||||
|
||||
+3
-3
@@ -68,20 +68,20 @@ abstract class GitLabApiTestCase {
|
||||
val glTests2Coordinates = GitLabProjectCoordinates(server, glTests2Project)
|
||||
val glTests2Label1 = GitLabLabelGQLDTO("label1", "#FFFFFF")
|
||||
val glTests2Label2 = GitLabLabelGQLDTO("label2", "#FFFFFF")
|
||||
val glTests2ProjectId = "6"
|
||||
|
||||
val glTest1Project = GitLabProjectPath("root", "gl-test-1")
|
||||
val glTest1Coordinates = GitLabProjectCoordinates(server, glTest1Project)
|
||||
val glTest1ProjectId = "2"
|
||||
|
||||
val glTest1Mr2Iid = "2"
|
||||
val glTest1Mr2CommitShas = listOf("6a7d70b5df2d77ad792bca08c6fb14e29ae4ad04")
|
||||
val glTest1Mr2CommitShortShas = listOf("6a7d70b5")
|
||||
val glTest1Mr2ChangedFiles = listOf("a/important.txt")
|
||||
|
||||
val volatileProject = GitLabProjectPath("volatile", "volatile-project")
|
||||
val volatileProjectCoordinates = GitLabProjectCoordinates(server, volatileProject)
|
||||
val volatileProjectMr1Iid = "1"
|
||||
val volatileProjectMr1Gid = "gid://gitlab/MergeRequest/5"
|
||||
val volatileProjectMr2Iid = "2"
|
||||
val volatileProjectId = "4"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+1
-2
@@ -38,7 +38,6 @@ import kotlinx.coroutines.flow.transformLatest
|
||||
import org.jetbrains.plugins.gitlab.GitLabServersManager
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApi
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabApiManager
|
||||
import org.jetbrains.plugins.gitlab.api.GitLabProjectCoordinates
|
||||
import org.jetbrains.plugins.gitlab.api.dto.WithGitLabNamespace
|
||||
import org.jetbrains.plugins.gitlab.api.request.findProject
|
||||
import org.jetbrains.plugins.gitlab.api.request.getMemberNamespacesForShare
|
||||
@@ -164,7 +163,7 @@ internal class GitLabShareProjectDialogViewModel(
|
||||
if (account == null || api == null || namespace == null) return@combine false
|
||||
|
||||
LOG.info("Checking for existing repositories at coordinates: ${account.server}/${namespace.fullPath}/$name")
|
||||
api.graphQL.findProject(GitLabProjectCoordinates(account.server, GitLabProjectPath(namespace.fullPath, name))).body() != null
|
||||
api.graphQL.findProject(GitLabProjectPath(namespace.fullPath, name)).body() != null
|
||||
}.stateIn(cs, SharingStarted.Eagerly, false)
|
||||
|
||||
private val accountValidationError: StateFlow<@NlsContexts.DialogMessage String?> =
|
||||
|
||||
Reference in New Issue
Block a user