org.octopusden.octopus.vcsfacade.service.impl.BitbucketService.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vcs-facade Show documentation
Show all versions of vcs-facade Show documentation
Octopus module: vcs-facade
The newest version!
package org.octopusden.octopus.vcsfacade.service.impl
import java.util.Date
import org.octopusden.octopus.infrastructure.bitbucket.client.BitbucketBasicCredentialProvider
import org.octopusden.octopus.infrastructure.bitbucket.client.BitbucketBearerTokenCredentialProvider
import org.octopusden.octopus.infrastructure.bitbucket.client.BitbucketClassicClient
import org.octopusden.octopus.infrastructure.bitbucket.client.BitbucketClient
import org.octopusden.octopus.infrastructure.bitbucket.client.BitbucketClientParametersProvider
import org.octopusden.octopus.infrastructure.bitbucket.client.BitbucketCredentialProvider
import org.octopusden.octopus.infrastructure.bitbucket.client.createPullRequestWithDefaultReviewers
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketBranch
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketCommit
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketCommitChange
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketCreateTag
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketPullRequest
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketPullRequestState
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketTag
import org.octopusden.octopus.infrastructure.bitbucket.client.dto.BitbucketUser
import org.octopusden.octopus.infrastructure.bitbucket.client.exception.NotFoundException
import org.octopusden.octopus.infrastructure.bitbucket.client.getBranches
import org.octopusden.octopus.infrastructure.bitbucket.client.getCommit
import org.octopusden.octopus.infrastructure.bitbucket.client.getCommitChanges
import org.octopusden.octopus.infrastructure.bitbucket.client.getCommits
import org.octopusden.octopus.infrastructure.bitbucket.client.getTag
import org.octopusden.octopus.infrastructure.bitbucket.client.getTags
import org.octopusden.octopus.vcsfacade.client.common.dto.Branch
import org.octopusden.octopus.vcsfacade.client.common.dto.Commit
import org.octopusden.octopus.vcsfacade.client.common.dto.CommitWithFiles
import org.octopusden.octopus.vcsfacade.client.common.dto.CreatePullRequest
import org.octopusden.octopus.vcsfacade.client.common.dto.CreateTag
import org.octopusden.octopus.vcsfacade.client.common.dto.FileChange
import org.octopusden.octopus.vcsfacade.client.common.dto.FileChangeType
import org.octopusden.octopus.vcsfacade.client.common.dto.PullRequest
import org.octopusden.octopus.vcsfacade.client.common.dto.PullRequestReviewer
import org.octopusden.octopus.vcsfacade.client.common.dto.PullRequestStatus
import org.octopusden.octopus.vcsfacade.client.common.dto.Repository
import org.octopusden.octopus.vcsfacade.client.common.dto.Tag
import org.octopusden.octopus.vcsfacade.client.common.dto.User
import org.octopusden.octopus.vcsfacade.config.VcsConfig
import org.octopusden.octopus.vcsfacade.dto.HashOrRefOrDate
import org.octopusden.octopus.vcsfacade.service.VcsService
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
@Service
@ConditionalOnProperty(
prefix = "vcs-facade.vcs.bitbucket", name = ["enabled"], havingValue = "true", matchIfMissing = true
)
class BitbucketService(
bitbucketProperties: VcsConfig.BitbucketProperties,
) : VcsService(bitbucketProperties) {
private val client: BitbucketClient = BitbucketClassicClient(object : BitbucketClientParametersProvider {
override fun getApiUrl(): String = httpUrl
override fun getAuth(): BitbucketCredentialProvider {
val authException by lazy {
IllegalStateException("Auth Token or username/password must be specified for Bitbucket access")
}
return bitbucketProperties.token?.let { BitbucketBearerTokenCredentialProvider(it) }
?: BitbucketBasicCredentialProvider(
bitbucketProperties.username ?: throw authException,
bitbucketProperties.password ?: throw authException
)
}
})
override val sshUrlRegex = "(?:ssh://)?git@$host/([^/]+)/([^/]+).git".toRegex()
override fun getBranches(group: String, repository: String): Sequence {
log.trace("=> getBranches({}, {})", group, repository)
return client.getBranches(group, repository).asSequence().map {
it.toBranch(group, repository)
}.also { log.trace("<= getBranches({}, {}): {}", group, repository, it) }
}
override fun getTags(group: String, repository: String): Sequence {
log.trace("=> getTags({}, {})", group, repository)
return client.getTags(group, repository).asSequence().map {
it.toTag(group, repository)
}.also { log.trace("<= getTags({}, {}): {}", group, repository, it) }
}
override fun createTag(group: String, repository: String, createTag: CreateTag): Tag {
log.trace("=> createTag({}, {}, {})", group, repository, createTag)
return client.createTag(
group, repository, BitbucketCreateTag(createTag.name, createTag.hashOrRef, createTag.message)
).toTag(group, repository).also {
log.trace("<= createTag({}, {}, {}): {}", group, repository, createTag, it)
}
}
override fun getTag(group: String, repository: String, name: String): Tag {
log.trace("=> getTag({}, {}, {})", group, repository, name)
return client.getTag(group, repository, name).toTag(group, repository).also {
log.trace("<= getTag({}, {}, {}): {}", group, repository, name, it)
}
}
override fun deleteTag(group: String, repository: String, name: String) {
log.trace("=> deleteTag({}, {}, {})", group, repository, name)
client.deleteTag(group, repository, name)
log.trace("<= deleteTag({}, {}, {})", group, repository, name)
}
override fun getCommits(
group: String,
repository: String,
from: HashOrRefOrDate?,
toHashOrRef: String
): Sequence {
log.trace("=> getCommits({}, {}, {}, {})", group, repository, from, toHashOrRef)
val commits = if (from is HashOrRefOrDate.HashOrRefValue) {
client.getCommits(group, repository, toHashOrRef, from.value)
} else {
client.getCommits(group, repository, toHashOrRef, (from as? HashOrRefOrDate.DateValue)?.value)
}
return commits.asSequence().map { it.toCommit(group, repository) }.also {
log.trace("<= getCommits({}, {}, {}, {}): {}", group, repository, from, toHashOrRef, it)
}
}
override fun getCommitsWithFiles(
group: String,
repository: String,
from: HashOrRefOrDate?,
toHashOrRef: String
): Sequence {
log.trace("=> getCommitsWithFiles({}, {}, {}, {})", group, repository, from, toHashOrRef)
return getCommits(group, repository, from, toHashOrRef).map {
val fileChanges = getCommitChanges(group, repository, it)
CommitWithFiles(it, fileChanges.size, fileChanges)
}.also { log.trace("<= getCommitsWithFiles({}, {}, {}, {}): {}", group, repository, from, toHashOrRef, it) }
}
override fun getCommit(group: String, repository: String, hashOrRef: String): Commit {
log.trace("=> getCommit({}, {}, {})", group, repository, hashOrRef)
return client.getCommit(group, repository, hashOrRef).toCommit(group, repository).also {
log.trace("<= getCommit({}, {}, {}): {}", group, repository, hashOrRef, it)
}
}
override fun getCommitWithFiles(group: String, repository: String, hashOrRef: String): CommitWithFiles {
log.trace("=> getCommitWithFiles({}, {}, {})", group, repository, hashOrRef)
return with(getCommit(group, repository, hashOrRef)) {
val fileChanges = getCommitChanges(group, repository, this)
CommitWithFiles(this, fileChanges.size, fileChanges)
}.also { log.trace("<= getCommitWithFiles({}, {}, {}): {}", group, repository, hashOrRef, it) }
}
override fun createPullRequest(
group: String, repository: String, createPullRequest: CreatePullRequest
): PullRequest {
log.trace("=> createPullRequest({}, {}, {})", group, repository, createPullRequest)
return client.createPullRequestWithDefaultReviewers(
group,
repository,
createPullRequest.sourceBranch,
createPullRequest.targetBranch,
createPullRequest.title,
createPullRequest.description
).toPullRequest(group, repository).also {
log.trace("<= createPullRequest({}, {}, {}): {}", group, repository, createPullRequest, it)
}
}
override fun getPullRequest(group: String, repository: String, index: Long): PullRequest {
log.trace("=> getPullRequest({}, {}, {})", group, repository, index)
return client.getPullRequest(group, repository, index).toPullRequest(group, repository).also {
log.trace("<= getPullRequest({}, {}, {}): {}", group, repository, index, it)
}
}
override fun findCommits(group: String, repository: String, hashes: Set): Sequence {
log.trace("=> findCommits({}, {}, {})", group, repository, hashes)
return hashes.mapNotNull {
try {
client.getCommit(group, repository, it).toCommit(group, repository)
} catch (e: NotFoundException) {
null
}
}.asSequence().also {
log.trace("<= findCommits({}, {}, {}): {}", group, repository, hashes, it)
}
}
override fun findPullRequests(group: String, repository: String, indexes: Set): Sequence {
log.trace("=> findPullRequests({}, {}, {})", group, repository, indexes)
return indexes.mapNotNull {
try {
client.getPullRequest(group, repository, it).toPullRequest(group, repository)
} catch (e: NotFoundException) {
null
}
}.asSequence().also {
log.trace("<= findPullRequests({}, {}, {}): {}", group, repository, indexes, it)
}
}
override fun findBranches(issueKey: String): Sequence {
log.warn("There is no native implementation of findBranches")
return emptySequence()
}
override fun findCommits(issueKey: String): Sequence {
log.trace("=> findCommits({})", issueKey)
return client.getCommits(issueKey).asSequence().map {
it.toCommit.toCommit(it.repository.project.key.lowercase(), it.repository.slug.lowercase())
}.also { log.trace("<= findCommits({}): {}", issueKey, it) }
}
override fun findCommitsWithFiles(issueKey: String): Sequence {
log.trace("=> findCommitsWithFiles({})", issueKey)
return client.getCommits(issueKey).asSequence().map {
val group = it.repository.project.key.lowercase()
val repository = it.repository.slug.lowercase()
val commit = it.toCommit.toCommit(group, repository)
val fileChanges = getCommitChanges(group, repository, commit)
CommitWithFiles(commit, fileChanges.size, fileChanges)
}.also { log.trace("<= findCommitsWithFiles({}): {}", issueKey, it) }
}
override fun findPullRequests(issueKey: String): Sequence {
log.warn("There is no native implementation of findPullRequests")
return emptySequence()
}
private fun getCommitChanges(group: String, repository: String, commit: Commit): List {
log.trace("=> getCommitChanges({}, {}, {})", group, repository, commit)
return client.getCommitChanges(group, repository, commit.hash).flatMap {
val files = mutableListOf(
FileChange(
when (it.type) {
BitbucketCommitChange.BitbucketCommitChangeType.ADD,
BitbucketCommitChange.BitbucketCommitChangeType.COPY,
BitbucketCommitChange.BitbucketCommitChangeType.MOVE -> FileChangeType.ADD
BitbucketCommitChange.BitbucketCommitChangeType.MODIFY -> FileChangeType.MODIFY
BitbucketCommitChange.BitbucketCommitChangeType.DELETE -> FileChangeType.DELETE
},
it.path.value,
"${commit.link}#${it.path.value}"
)
)
if (it.type == BitbucketCommitChange.BitbucketCommitChangeType.MOVE) {
files.add(FileChange(FileChangeType.DELETE, it.srcPath!!.value, "${commit.link}#${it.srcPath!!.value}"))
}
files
}.also { log.trace("<= getCommitChanges({}, {}, {}): {}", group, repository, commit, it) }
}
private fun getRepository(project: String, repository: String) = Repository(
"ssh://git@$host/$project/$repository.git",
"$httpUrl/projects/$project/repos/$repository/browse",
"$httpUrl/projects/$project/avatar.png?s=48"
)
private fun BitbucketBranch.toBranch(project: String, repository: String) = Branch(
displayId,
latestCommit,
"$httpUrl/projects/$project/repos/$repository/browse?at=$displayId",
getRepository(project, repository)
)
private fun BitbucketTag.toTag(project: String, repository: String) = Tag(
displayId,
latestCommit,
"$httpUrl/projects/$project/repos/$repository/browse?at=$displayId",
getRepository(project, repository)
)
private fun BitbucketUser.toUser() = User(name, "$httpUrl/users/$name/avatar.png?s=48")
private fun BitbucketCommit.toCommit(project: String, repository: String) = Commit(
id,
message,
authorTimestamp,
author.toUser(),
parents.map { it.id },
"$httpUrl/projects/$project/repos/$repository/commits/$id",
getRepository(project, repository)
)
private fun BitbucketPullRequest.toPullRequest(project: String, repository: String) =
author.user.toUser().let { author ->
PullRequest(
id,
title,
description ?: "",
author,
fromRef.displayId,
toRef.displayId,
emptyList(),
reviewers.map { PullRequestReviewer(it.user.toUser(), it.approved) },
when (state) {
BitbucketPullRequestState.MERGED -> PullRequestStatus.MERGED
BitbucketPullRequestState.DECLINED -> PullRequestStatus.DECLINED
BitbucketPullRequestState.OPEN -> PullRequestStatus.OPEN
},
createdDate,
updatedDate,
"$httpUrl/projects/$project/repos/$repository/pull-requests/$id/overview",
getRepository(project, repository)
)
}
companion object {
private val log = LoggerFactory.getLogger(BitbucketService::class.java)
}
}