Started arch refactor
This commit is contained in:
parent
cbcb13d730
commit
270951fe66
@ -1,61 +0,0 @@
|
|||||||
package app.git
|
|
||||||
|
|
||||||
import app.models.AuthorInfo
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.eclipse.jgit.api.Git
|
|
||||||
import org.eclipse.jgit.storage.file.FileBasedConfig
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class AuthorManager @Inject constructor() {
|
|
||||||
suspend fun loadAuthor(git: Git) = withContext(Dispatchers.IO) {
|
|
||||||
val config = git.repository.config
|
|
||||||
val globalConfig = git.repository.config.baseConfig
|
|
||||||
|
|
||||||
val repoConfig = FileBasedConfig((config as FileBasedConfig).file, git.repository.fs)
|
|
||||||
repoConfig.load()
|
|
||||||
|
|
||||||
val globalName = globalConfig.getString("user", null, "name")
|
|
||||||
val globalEmail = globalConfig.getString("user", null, "email")
|
|
||||||
|
|
||||||
val name = repoConfig.getString("user", null, "name")
|
|
||||||
val email = repoConfig.getString("user", null, "email")
|
|
||||||
|
|
||||||
return@withContext AuthorInfo(
|
|
||||||
globalName,
|
|
||||||
globalEmail,
|
|
||||||
name,
|
|
||||||
email,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun saveAuthorInfo(git: Git, newAuthorInfo: AuthorInfo) = withContext(Dispatchers.IO) {
|
|
||||||
val config = git.repository.config
|
|
||||||
val globalConfig = git.repository.config.baseConfig
|
|
||||||
val repoConfig = FileBasedConfig((config as FileBasedConfig).file, git.repository.fs)
|
|
||||||
repoConfig.load()
|
|
||||||
|
|
||||||
if (globalConfig is FileBasedConfig) {
|
|
||||||
globalConfig.setStringProperty("user", null, "name", newAuthorInfo.globalName)
|
|
||||||
globalConfig.setStringProperty("user", null, "email", newAuthorInfo.globalEmail)
|
|
||||||
globalConfig.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
config.setStringProperty("user", null, "name", newAuthorInfo.name)
|
|
||||||
config.setStringProperty("user", null, "email", newAuthorInfo.email)
|
|
||||||
config.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FileBasedConfig.setStringProperty(
|
|
||||||
section: String,
|
|
||||||
subsection: String?,
|
|
||||||
name: String,
|
|
||||||
value: String?,
|
|
||||||
) {
|
|
||||||
if (value == null) {
|
|
||||||
unset(section, subsection, name)
|
|
||||||
} else {
|
|
||||||
setString(section, subsection, name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
package app.git
|
|
||||||
|
|
||||||
import app.extensions.isBranch
|
|
||||||
import app.extensions.simpleName
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.eclipse.jgit.api.CreateBranchCommand
|
|
||||||
import org.eclipse.jgit.api.Git
|
|
||||||
import org.eclipse.jgit.api.ListBranchCommand
|
|
||||||
import org.eclipse.jgit.lib.Ref
|
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class BranchesManager @Inject constructor() {
|
|
||||||
/**
|
|
||||||
* Returns the current branch in [Ref]. If the repository is new, the current branch will be null.
|
|
||||||
*/
|
|
||||||
suspend fun currentBranchRef(git: Git): Ref? {
|
|
||||||
val branchList = getBranches(git)
|
|
||||||
val branchName = git
|
|
||||||
.repository
|
|
||||||
.fullBranch
|
|
||||||
|
|
||||||
var branchFound = branchList.firstOrNull {
|
|
||||||
it.name == branchName
|
|
||||||
}
|
|
||||||
|
|
||||||
if (branchFound == null) {
|
|
||||||
branchFound = branchList.firstOrNull {
|
|
||||||
it.objectId.name == branchName // Try to get the HEAD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return branchFound
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getBranches(git: Git) = withContext(Dispatchers.IO) {
|
|
||||||
return@withContext git
|
|
||||||
.branchList()
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun createBranch(git: Git, branchName: String) = withContext(Dispatchers.IO) {
|
|
||||||
git
|
|
||||||
.checkout()
|
|
||||||
.setCreateBranch(true)
|
|
||||||
.setName(branchName)
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun createBranchOnCommit(git: Git, branch: String, revCommit: RevCommit) = withContext(Dispatchers.IO) {
|
|
||||||
git
|
|
||||||
.checkout()
|
|
||||||
.setCreateBranch(true)
|
|
||||||
.setName(branch)
|
|
||||||
.setStartPoint(revCommit)
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun deleteBranch(git: Git, branch: Ref) = withContext(Dispatchers.IO) {
|
|
||||||
git
|
|
||||||
.branchDelete()
|
|
||||||
.setBranchNames(branch.name)
|
|
||||||
.setForce(true) // TODO Should it be forced?
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun deleteLocallyRemoteBranches(git: Git, branches: List<String>) = withContext(Dispatchers.IO) {
|
|
||||||
git
|
|
||||||
.branchDelete()
|
|
||||||
.setBranchNames(*branches.toTypedArray())
|
|
||||||
.setForce(true)
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun remoteBranches(git: Git) = withContext(Dispatchers.IO) {
|
|
||||||
git
|
|
||||||
.branchList()
|
|
||||||
.setListMode(ListBranchCommand.ListMode.REMOTE)
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun checkoutRef(git: Git, ref: Ref) = withContext(Dispatchers.IO) {
|
|
||||||
git.checkout().apply {
|
|
||||||
setName(ref.name)
|
|
||||||
if (ref.isBranch && ref.name.startsWith("refs/remotes/")) {
|
|
||||||
setCreateBranch(true)
|
|
||||||
setName(ref.simpleName)
|
|
||||||
setStartPoint(ref.objectId.name)
|
|
||||||
setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
|
|
||||||
}
|
|
||||||
call()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
34
src/main/kotlin/app/git/CloneStatus.kt
Normal file
34
src/main/kotlin/app/git/CloneStatus.kt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package app.git
|
||||||
|
|
||||||
|
import org.eclipse.jgit.transport.RemoteRefUpdate
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
sealed class CloneStatus {
|
||||||
|
object None : CloneStatus()
|
||||||
|
data class Cloning(val taskName: String, val progress: Int, val total: Int) : CloneStatus()
|
||||||
|
object Cancelling : CloneStatus()
|
||||||
|
data class Fail(val reason: String) : CloneStatus()
|
||||||
|
data class Completed(val repoDir: File) : CloneStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
val RemoteRefUpdate.Status.isRejected: Boolean
|
||||||
|
get() {
|
||||||
|
return this == RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD ||
|
||||||
|
this == RemoteRefUpdate.Status.REJECTED_NODELETE ||
|
||||||
|
this == RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED ||
|
||||||
|
this == RemoteRefUpdate.Status.REJECTED_OTHER_REASON
|
||||||
|
}
|
||||||
|
|
||||||
|
val RemoteRefUpdate.statusMessage: String
|
||||||
|
get() {
|
||||||
|
return when (this.status) {
|
||||||
|
RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD -> "Failed to push some refs to ${this.remoteName}. " +
|
||||||
|
"Updates were rejected because the remote contains work that you do not have locally. Pulling changes from remote may help."
|
||||||
|
|
||||||
|
RemoteRefUpdate.Status.REJECTED_NODELETE -> "Could not delete ref because the remote doesn't support deleting refs."
|
||||||
|
RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED -> "Ref rejected, old object id in remote has changed."
|
||||||
|
RemoteRefUpdate.Status.REJECTED_OTHER_REASON -> this.message ?: "Push rejected for unknown reasons."
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,7 @@ import app.di.RawFileManagerFactory
|
|||||||
import app.exceptions.MissingDiffEntryException
|
import app.exceptions.MissingDiffEntryException
|
||||||
import app.extensions.fullData
|
import app.extensions.fullData
|
||||||
import app.extensions.isMerging
|
import app.extensions.isMerging
|
||||||
|
import app.git.branches.GetCurrentBranchUseCase
|
||||||
import app.git.diff.DiffResult
|
import app.git.diff.DiffResult
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -28,7 +29,7 @@ import javax.inject.Inject
|
|||||||
class DiffManager @Inject constructor(
|
class DiffManager @Inject constructor(
|
||||||
private val rawFileManagerFactory: RawFileManagerFactory,
|
private val rawFileManagerFactory: RawFileManagerFactory,
|
||||||
private val hunkDiffGeneratorFactory: HunkDiffGeneratorFactory,
|
private val hunkDiffGeneratorFactory: HunkDiffGeneratorFactory,
|
||||||
private val branchesManager: BranchesManager,
|
private val getCurrentBranchUseCase: GetCurrentBranchUseCase,
|
||||||
private val repositoryManager: RepositoryManager,
|
private val repositoryManager: RepositoryManager,
|
||||||
) {
|
) {
|
||||||
suspend fun diffFormat(git: Git, diffEntryType: DiffEntryType): DiffResult = withContext(Dispatchers.IO) {
|
suspend fun diffFormat(git: Git, diffEntryType: DiffEntryType): DiffResult = withContext(Dispatchers.IO) {
|
||||||
@ -57,7 +58,7 @@ class DiffManager @Inject constructor(
|
|||||||
.setCached(cached).apply {
|
.setCached(cached).apply {
|
||||||
val repositoryState = repositoryManager.getRepositoryState(git)
|
val repositoryState = repositoryManager.getRepositoryState(git)
|
||||||
if (
|
if (
|
||||||
branchesManager.currentBranchRef(git) == null &&
|
getCurrentBranchUseCase(git) == null &&
|
||||||
!repositoryState.isMerging &&
|
!repositoryState.isMerging &&
|
||||||
!repositoryState.isRebasing &&
|
!repositoryState.isRebasing &&
|
||||||
cached
|
cached
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app.git
|
package app.git
|
||||||
|
|
||||||
import app.exceptions.UncommitedChangesDetectedException
|
import app.exceptions.UncommitedChangesDetectedException
|
||||||
|
import app.git.branches.GetCurrentBranchUseCase
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
@ -16,7 +17,7 @@ import org.eclipse.jgit.revwalk.RevWalk
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RebaseManager @Inject constructor(
|
class RebaseManager @Inject constructor(
|
||||||
private val branchesManager: BranchesManager,
|
private val getCurrentBranchUseCase: GetCurrentBranchUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun rebaseBranch(git: Git, ref: Ref) = withContext(Dispatchers.IO) {
|
suspend fun rebaseBranch(git: Git, ref: Ref) = withContext(Dispatchers.IO) {
|
||||||
@ -127,7 +128,7 @@ class RebaseManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun markCurrentBranchAsStart(revWalk: RevWalk, git: Git) {
|
private suspend fun markCurrentBranchAsStart(revWalk: RevWalk, git: Git) {
|
||||||
val currentBranch = branchesManager.currentBranchRef(git) ?: throw Exception("Null current branch")
|
val currentBranch = getCurrentBranchUseCase(git) ?: throw Exception("Null current branch")
|
||||||
val refTarget = revWalk.parseAny(currentBranch.leaf.objectId)
|
val refTarget = revWalk.parseAny(currentBranch.leaf.objectId)
|
||||||
|
|
||||||
if (refTarget is RevCommit)
|
if (refTarget is RevCommit)
|
||||||
|
@ -1,297 +0,0 @@
|
|||||||
package app.git
|
|
||||||
|
|
||||||
import app.credentials.GSessionManager
|
|
||||||
import app.credentials.HttpCredentialsProvider
|
|
||||||
import app.extensions.remoteName
|
|
||||||
import app.extensions.simpleName
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
|
||||||
import org.eclipse.jgit.api.Git
|
|
||||||
import org.eclipse.jgit.api.RebaseResult
|
|
||||||
import org.eclipse.jgit.lib.ProgressMonitor
|
|
||||||
import org.eclipse.jgit.lib.Ref
|
|
||||||
import org.eclipse.jgit.transport.*
|
|
||||||
import java.io.File
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlin.coroutines.cancellation.CancellationException
|
|
||||||
|
|
||||||
|
|
||||||
class RemoteOperationsManager @Inject constructor(
|
|
||||||
private val sessionManager: GSessionManager
|
|
||||||
) {
|
|
||||||
suspend fun pull(git: Git, rebase: Boolean) = withContext(Dispatchers.IO) {
|
|
||||||
val pullResult = git
|
|
||||||
.pull()
|
|
||||||
.setTransportConfigCallback {
|
|
||||||
handleTransportCredentials(it)
|
|
||||||
}
|
|
||||||
.setRebase(rebase)
|
|
||||||
.setCredentialsProvider(CredentialsProvider.getDefault())
|
|
||||||
.call()
|
|
||||||
|
|
||||||
if (!pullResult.isSuccessful) {
|
|
||||||
var message = "Pull failed"
|
|
||||||
|
|
||||||
if (rebase) {
|
|
||||||
message = when (pullResult.rebaseResult.status) {
|
|
||||||
RebaseResult.Status.UNCOMMITTED_CHANGES -> "The pull with rebase has failed because you have got uncommited changes"
|
|
||||||
RebaseResult.Status.CONFLICTS -> "Pull with rebase has conflicts, fix them to continue"
|
|
||||||
else -> message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Exception(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun pullFromBranch(git: Git, rebase: Boolean, remoteBranch: Ref) = withContext(Dispatchers.IO) {
|
|
||||||
val pullResult = git
|
|
||||||
.pull()
|
|
||||||
.setTransportConfigCallback {
|
|
||||||
handleTransportCredentials(it)
|
|
||||||
}
|
|
||||||
.setRemote(remoteBranch.remoteName)
|
|
||||||
.setRemoteBranchName(remoteBranch.simpleName)
|
|
||||||
.setRebase(rebase)
|
|
||||||
.setCredentialsProvider(CredentialsProvider.getDefault())
|
|
||||||
.call()
|
|
||||||
|
|
||||||
if (!pullResult.isSuccessful) {
|
|
||||||
var message = "Pull failed"
|
|
||||||
|
|
||||||
if (rebase) {
|
|
||||||
message = when (pullResult.rebaseResult.status) {
|
|
||||||
RebaseResult.Status.UNCOMMITTED_CHANGES -> "The pull with rebase has failed because you have got uncommited changes"
|
|
||||||
RebaseResult.Status.CONFLICTS -> "Pull with rebase has conflicts, fix them to continue"
|
|
||||||
else -> message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Exception(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun fetchAll(git: Git) = withContext(Dispatchers.IO) {
|
|
||||||
val remotes = git.remoteList().call()
|
|
||||||
|
|
||||||
for (remote in remotes) {
|
|
||||||
git.fetch()
|
|
||||||
.setRemote(remote.name)
|
|
||||||
.setRefSpecs(remote.fetchRefSpecs)
|
|
||||||
.setTransportConfigCallback {
|
|
||||||
handleTransportCredentials(it)
|
|
||||||
}
|
|
||||||
.setCredentialsProvider(CredentialsProvider.getDefault())
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun push(git: Git, force: Boolean, pushTags: Boolean) = withContext(Dispatchers.IO) {
|
|
||||||
val currentBranchRefSpec = git.repository.fullBranch
|
|
||||||
|
|
||||||
val pushResult = git
|
|
||||||
.push()
|
|
||||||
.setRefSpecs(RefSpec(currentBranchRefSpec))
|
|
||||||
.setForce(force)
|
|
||||||
.apply {
|
|
||||||
if (pushTags)
|
|
||||||
setPushTags()
|
|
||||||
}
|
|
||||||
.setTransportConfigCallback {
|
|
||||||
handleTransportCredentials(it)
|
|
||||||
}
|
|
||||||
.call()
|
|
||||||
|
|
||||||
val results =
|
|
||||||
pushResult.map { it.remoteUpdates.filter { remoteRefUpdate -> remoteRefUpdate.status.isRejected } }
|
|
||||||
.flatten()
|
|
||||||
if (results.isNotEmpty()) {
|
|
||||||
val error = StringBuilder()
|
|
||||||
|
|
||||||
results.forEach { result ->
|
|
||||||
error.append(result.statusMessage)
|
|
||||||
error.append("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Exception(error.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun pushToBranch(git: Git, force: Boolean, pushTags: Boolean, remoteBranch: Ref) =
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val currentBranchRefSpec = git.repository.fullBranch
|
|
||||||
|
|
||||||
val pushResult = git
|
|
||||||
.push()
|
|
||||||
.setRefSpecs(RefSpec("$currentBranchRefSpec:${remoteBranch.simpleName}"))
|
|
||||||
.setRemote(remoteBranch.remoteName)
|
|
||||||
.setForce(force)
|
|
||||||
.apply {
|
|
||||||
if (pushTags)
|
|
||||||
setPushTags()
|
|
||||||
}
|
|
||||||
.setTransportConfigCallback {
|
|
||||||
handleTransportCredentials(it)
|
|
||||||
}
|
|
||||||
.call()
|
|
||||||
|
|
||||||
val results =
|
|
||||||
pushResult.map { it.remoteUpdates.filter { remoteRefUpdate -> remoteRefUpdate.status.isRejected } }
|
|
||||||
.flatten()
|
|
||||||
if (results.isNotEmpty()) {
|
|
||||||
val error = StringBuilder()
|
|
||||||
|
|
||||||
results.forEach { result ->
|
|
||||||
error.append(result.statusMessage)
|
|
||||||
error.append("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Exception(error.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleTransportCredentials(transport: Transport?) {
|
|
||||||
if (transport is SshTransport) {
|
|
||||||
transport.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
|
||||||
} else if (transport is HttpTransport) {
|
|
||||||
transport.credentialsProvider = HttpCredentialsProvider()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun deleteBranch(git: Git, ref: Ref) = withContext(Dispatchers.IO) {
|
|
||||||
val branchSplit = ref.name.split("/").toMutableList()
|
|
||||||
val remoteName = branchSplit[2] // Remote name
|
|
||||||
repeat(3) {
|
|
||||||
branchSplit.removeAt(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val branchName = "refs/heads/${branchSplit.joinToString("/")}"
|
|
||||||
|
|
||||||
val refSpec = RefSpec()
|
|
||||||
.setSource(null)
|
|
||||||
.setDestination(branchName)
|
|
||||||
|
|
||||||
val pushResult = git.push()
|
|
||||||
.setTransportConfigCallback {
|
|
||||||
handleTransportCredentials(it)
|
|
||||||
}
|
|
||||||
.setRefSpecs(refSpec)
|
|
||||||
.setRemote(remoteName)
|
|
||||||
.call()
|
|
||||||
|
|
||||||
val results =
|
|
||||||
pushResult.map { it.remoteUpdates.filter { remoteRefUpdate -> remoteRefUpdate.status.isRejected } }
|
|
||||||
.flatten()
|
|
||||||
if (results.isNotEmpty()) {
|
|
||||||
val error = StringBuilder()
|
|
||||||
|
|
||||||
results.forEach { result ->
|
|
||||||
error.append(result.statusMessage)
|
|
||||||
error.append("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Exception(error.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
git
|
|
||||||
.branchDelete()
|
|
||||||
.setBranchNames(ref.name)
|
|
||||||
.call()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val RemoteRefUpdate.Status.isRejected: Boolean
|
|
||||||
get() {
|
|
||||||
return this == RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD ||
|
|
||||||
this == RemoteRefUpdate.Status.REJECTED_NODELETE ||
|
|
||||||
this == RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED ||
|
|
||||||
this == RemoteRefUpdate.Status.REJECTED_OTHER_REASON
|
|
||||||
}
|
|
||||||
|
|
||||||
private val RemoteRefUpdate.statusMessage: String
|
|
||||||
get() {
|
|
||||||
return when (this.status) {
|
|
||||||
RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD -> "Failed to push some refs to ${this.remoteName}. " +
|
|
||||||
"Updates were rejected because the remote contains work that you do not have locally. Pulling changes from remote may help."
|
|
||||||
RemoteRefUpdate.Status.REJECTED_NODELETE -> "Could not delete ref because the remote doesn't support deleting refs."
|
|
||||||
RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED -> "Ref rejected, old object id in remote has changed."
|
|
||||||
RemoteRefUpdate.Status.REJECTED_OTHER_REASON -> this.message ?: "Push rejected for unknown reasons."
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
fun clone(directory: File, url: String): Flow<CloneStatus> = callbackFlow {
|
|
||||||
var lastTitle: String = ""
|
|
||||||
var lastTotalWork = 0
|
|
||||||
var progress = 0
|
|
||||||
|
|
||||||
try {
|
|
||||||
ensureActive()
|
|
||||||
trySend(CloneStatus.Cloning("Starting...", progress, lastTotalWork))
|
|
||||||
|
|
||||||
Git.cloneRepository()
|
|
||||||
.setDirectory(directory)
|
|
||||||
.setURI(url)
|
|
||||||
.setProgressMonitor(
|
|
||||||
object : ProgressMonitor {
|
|
||||||
override fun start(totalTasks: Int) {
|
|
||||||
println("ProgressMonitor Start with total tasks of: $totalTasks")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun beginTask(title: String?, totalWork: Int) {
|
|
||||||
println("ProgressMonitor Begin task with title: $title")
|
|
||||||
lastTitle = title.orEmpty()
|
|
||||||
lastTotalWork = totalWork
|
|
||||||
progress = 0
|
|
||||||
trySend(CloneStatus.Cloning(lastTitle, progress, lastTotalWork))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(completed: Int) {
|
|
||||||
println("ProgressMonitor Update $completed")
|
|
||||||
ensureActive()
|
|
||||||
|
|
||||||
progress += completed
|
|
||||||
trySend(CloneStatus.Cloning(lastTitle, progress, lastTotalWork))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun endTask() {
|
|
||||||
println("ProgressMonitor End task")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isCancelled(): Boolean {
|
|
||||||
return !isActive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.setTransportConfigCallback {
|
|
||||||
handleTransportCredentials(it)
|
|
||||||
}
|
|
||||||
.call()
|
|
||||||
|
|
||||||
ensureActive()
|
|
||||||
trySend(CloneStatus.Completed(directory))
|
|
||||||
channel.close()
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
if (ex.cause?.cause is CancellationException) {
|
|
||||||
println("Clone cancelled")
|
|
||||||
} else {
|
|
||||||
trySend(CloneStatus.Fail(ex.localizedMessage))
|
|
||||||
}
|
|
||||||
|
|
||||||
channel.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
awaitClose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class CloneStatus {
|
|
||||||
object None : CloneStatus()
|
|
||||||
data class Cloning(val taskName: String, val progress: Int, val total: Int) : CloneStatus()
|
|
||||||
object Cancelling : CloneStatus()
|
|
||||||
data class Fail(val reason: String) : CloneStatus()
|
|
||||||
data class Completed(val repoDir: File) : CloneStatus()
|
|
||||||
}
|
|
31
src/main/kotlin/app/git/author/LoadAuthorUseCase.kt
Normal file
31
src/main/kotlin/app/git/author/LoadAuthorUseCase.kt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package app.git.author
|
||||||
|
|
||||||
|
import app.models.AuthorInfo
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.storage.file.FileBasedConfig
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LoadAuthorUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git): AuthorInfo = withContext(Dispatchers.IO) {
|
||||||
|
val config = git.repository.config
|
||||||
|
val globalConfig = git.repository.config.baseConfig
|
||||||
|
|
||||||
|
val repoConfig = FileBasedConfig((config as FileBasedConfig).file, git.repository.fs)
|
||||||
|
repoConfig.load()
|
||||||
|
|
||||||
|
val globalName = globalConfig.getString("user", null, "name")
|
||||||
|
val globalEmail = globalConfig.getString("user", null, "email")
|
||||||
|
|
||||||
|
val name = repoConfig.getString("user", null, "name")
|
||||||
|
val email = repoConfig.getString("user", null, "email")
|
||||||
|
|
||||||
|
return@withContext AuthorInfo(
|
||||||
|
globalName,
|
||||||
|
globalEmail,
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
40
src/main/kotlin/app/git/author/SaveAuthorUseCase.kt
Normal file
40
src/main/kotlin/app/git/author/SaveAuthorUseCase.kt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package app.git.author
|
||||||
|
|
||||||
|
import app.models.AuthorInfo
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.storage.file.FileBasedConfig
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SaveAuthorUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git, newAuthorInfo: AuthorInfo) = withContext(Dispatchers.IO) {
|
||||||
|
val config = git.repository.config
|
||||||
|
val globalConfig = git.repository.config.baseConfig
|
||||||
|
val repoConfig = FileBasedConfig((config as FileBasedConfig).file, git.repository.fs)
|
||||||
|
repoConfig.load()
|
||||||
|
|
||||||
|
if (globalConfig is FileBasedConfig) {
|
||||||
|
globalConfig.setStringProperty("user", null, "name", newAuthorInfo.globalName)
|
||||||
|
globalConfig.setStringProperty("user", null, "email", newAuthorInfo.globalEmail)
|
||||||
|
globalConfig.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
config.setStringProperty("user", null, "name", newAuthorInfo.name)
|
||||||
|
config.setStringProperty("user", null, "email", newAuthorInfo.email)
|
||||||
|
config.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FileBasedConfig.setStringProperty(
|
||||||
|
section: String,
|
||||||
|
subsection: String?,
|
||||||
|
name: String,
|
||||||
|
value: String?,
|
||||||
|
) {
|
||||||
|
if (value == null) {
|
||||||
|
unset(section, subsection, name)
|
||||||
|
} else {
|
||||||
|
setString(section, subsection, name, value)
|
||||||
|
}
|
||||||
|
}
|
25
src/main/kotlin/app/git/branches/CheckoutRefUseCase.kt
Normal file
25
src/main/kotlin/app/git/branches/CheckoutRefUseCase.kt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import app.extensions.isBranch
|
||||||
|
import app.extensions.simpleName
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.CreateBranchCommand
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CheckoutRefUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git, ref: Ref): Unit = withContext(Dispatchers.IO) {
|
||||||
|
git.checkout().apply {
|
||||||
|
setName(ref.name)
|
||||||
|
if (ref.isBranch && ref.name.startsWith("refs/remotes/")) {
|
||||||
|
setCreateBranch(true)
|
||||||
|
setName(ref.simpleName)
|
||||||
|
setStartPoint(ref.objectId.name)
|
||||||
|
setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
|
||||||
|
}
|
||||||
|
call()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CreateBranchOnCommitUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git, branch: String, revCommit: RevCommit): Ref = withContext(Dispatchers.IO) {
|
||||||
|
git
|
||||||
|
.checkout()
|
||||||
|
.setCreateBranch(true)
|
||||||
|
.setName(branch)
|
||||||
|
.setStartPoint(revCommit)
|
||||||
|
.call()
|
||||||
|
}
|
||||||
|
}
|
17
src/main/kotlin/app/git/branches/CreateBranchUseCase.kt
Normal file
17
src/main/kotlin/app/git/branches/CreateBranchUseCase.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CreateBranchUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git, branchName: String): Ref = withContext(Dispatchers.IO) {
|
||||||
|
git
|
||||||
|
.checkout()
|
||||||
|
.setCreateBranch(true)
|
||||||
|
.setName(branchName)
|
||||||
|
.call()
|
||||||
|
}
|
||||||
|
}
|
17
src/main/kotlin/app/git/branches/DeleteBranchUseCase.kt
Normal file
17
src/main/kotlin/app/git/branches/DeleteBranchUseCase.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DeleteBranchUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git, branch: Ref): List<String> = withContext(Dispatchers.IO) {
|
||||||
|
git
|
||||||
|
.branchDelete()
|
||||||
|
.setBranchNames(branch.name)
|
||||||
|
.setForce(true) // TODO Should it be forced?
|
||||||
|
.call()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DeleteLocallyRemoteBranches @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git, branches: List<String>): List<String> = withContext(Dispatchers.IO) {
|
||||||
|
git
|
||||||
|
.branchDelete()
|
||||||
|
.setBranchNames(*branches.toTypedArray())
|
||||||
|
.setForce(true)
|
||||||
|
.call()
|
||||||
|
}
|
||||||
|
}
|
15
src/main/kotlin/app/git/branches/GetBranchesUseCase.kt
Normal file
15
src/main/kotlin/app/git/branches/GetBranchesUseCase.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GetBranchesUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git): List<Ref> = withContext(Dispatchers.IO) {
|
||||||
|
return@withContext git
|
||||||
|
.branchList()
|
||||||
|
.call()
|
||||||
|
}
|
||||||
|
}
|
31
src/main/kotlin/app/git/branches/GetCurrentBranchUseCase.kt
Normal file
31
src/main/kotlin/app/git/branches/GetCurrentBranchUseCase.kt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current branch in [Ref]. If the repository is new, the current branch will be null.
|
||||||
|
*/
|
||||||
|
class GetCurrentBranchUseCase @Inject constructor(
|
||||||
|
private val getBranchesUseCase: GetBranchesUseCase,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(git: Git): Ref? {
|
||||||
|
val branchList = getBranchesUseCase(git)
|
||||||
|
val branchName = git
|
||||||
|
.repository
|
||||||
|
.fullBranch
|
||||||
|
|
||||||
|
var branchFound = branchList.firstOrNull {
|
||||||
|
it.name == branchName
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branchFound == null) {
|
||||||
|
branchFound = branchList.firstOrNull {
|
||||||
|
it.objectId.name == branchName // Try to get the HEAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return branchFound
|
||||||
|
}
|
||||||
|
}
|
17
src/main/kotlin/app/git/branches/GetRemoteBranchesUseCase.kt
Normal file
17
src/main/kotlin/app/git/branches/GetRemoteBranchesUseCase.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package app.git.branches
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.api.ListBranchCommand
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GetRemoteBranchesUseCase @Inject constructor() {
|
||||||
|
suspend operator fun invoke(git: Git): List<Ref> = withContext(Dispatchers.IO) {
|
||||||
|
git
|
||||||
|
.branchList()
|
||||||
|
.setListMode(ListBranchCommand.ListMode.REMOTE)
|
||||||
|
.call()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import app.git.CloneStatus
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.ensureActive
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.ProgressMonitor
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CloneRepositoryUseCase @Inject constructor(
|
||||||
|
private val handleTransportUseCase: HandleTransportUseCase,
|
||||||
|
) {
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
operator fun invoke(directory: File, url: String): Flow<CloneStatus> = callbackFlow {
|
||||||
|
var lastTitle: String = ""
|
||||||
|
var lastTotalWork = 0
|
||||||
|
var progress = 0
|
||||||
|
|
||||||
|
try {
|
||||||
|
ensureActive()
|
||||||
|
trySend(CloneStatus.Cloning("Starting...", progress, lastTotalWork))
|
||||||
|
|
||||||
|
Git.cloneRepository()
|
||||||
|
.setDirectory(directory)
|
||||||
|
.setURI(url)
|
||||||
|
.setProgressMonitor(
|
||||||
|
object : ProgressMonitor {
|
||||||
|
override fun start(totalTasks: Int) {
|
||||||
|
println("ProgressMonitor Start with total tasks of: $totalTasks")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beginTask(title: String?, totalWork: Int) {
|
||||||
|
println("ProgressMonitor Begin task with title: $title")
|
||||||
|
lastTitle = title.orEmpty()
|
||||||
|
lastTotalWork = totalWork
|
||||||
|
progress = 0
|
||||||
|
trySend(CloneStatus.Cloning(lastTitle, progress, lastTotalWork))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(completed: Int) {
|
||||||
|
println("ProgressMonitor Update $completed")
|
||||||
|
ensureActive()
|
||||||
|
|
||||||
|
progress += completed
|
||||||
|
trySend(CloneStatus.Cloning(lastTitle, progress, lastTotalWork))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endTask() {
|
||||||
|
println("ProgressMonitor End task")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isCancelled(): Boolean {
|
||||||
|
return !isActive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.setTransportConfigCallback { handleTransportUseCase(it) }
|
||||||
|
.call()
|
||||||
|
|
||||||
|
ensureActive()
|
||||||
|
trySend(CloneStatus.Completed(directory))
|
||||||
|
channel.close()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (ex.cause?.cause is CancellationException) {
|
||||||
|
println("Clone cancelled")
|
||||||
|
} else {
|
||||||
|
trySend(CloneStatus.Fail(ex.localizedMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
awaitClose()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import app.git.branches.DeleteBranchUseCase
|
||||||
|
import app.git.isRejected
|
||||||
|
import app.git.statusMessage
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import org.eclipse.jgit.transport.RefSpec
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DeleteRemoteBranchUseCase @Inject constructor(
|
||||||
|
private val handleTransportUseCase: HandleTransportUseCase,
|
||||||
|
private val deleteBranchUseCase: DeleteBranchUseCase,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(git: Git, ref: Ref) {
|
||||||
|
val branchSplit = ref.name.split("/").toMutableList()
|
||||||
|
val remoteName = branchSplit[2] // Remote name
|
||||||
|
repeat(3) {
|
||||||
|
branchSplit.removeAt(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val branchName = "refs/heads/${branchSplit.joinToString("/")}"
|
||||||
|
|
||||||
|
val refSpec = RefSpec()
|
||||||
|
.setSource(null)
|
||||||
|
.setDestination(branchName)
|
||||||
|
|
||||||
|
val pushResults = git.push()
|
||||||
|
.setTransportConfigCallback {
|
||||||
|
handleTransportUseCase(it)
|
||||||
|
}
|
||||||
|
.setRefSpecs(refSpec)
|
||||||
|
.setRemote(remoteName)
|
||||||
|
.call()
|
||||||
|
|
||||||
|
val results = pushResults.map { pushResult ->
|
||||||
|
pushResult.remoteUpdates.filter { remoteRefUpdate ->
|
||||||
|
remoteRefUpdate.status.isRejected
|
||||||
|
}
|
||||||
|
}.flatten()
|
||||||
|
|
||||||
|
if (results.isNotEmpty()) {
|
||||||
|
val error = StringBuilder()
|
||||||
|
|
||||||
|
results.forEach { result ->
|
||||||
|
error.append(result.statusMessage)
|
||||||
|
error.append("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(error.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteBranchUseCase(git, ref)
|
||||||
|
// git
|
||||||
|
// .branchDelete()
|
||||||
|
// .setBranchNames(ref.name)
|
||||||
|
// .call()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.transport.CredentialsProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class FetchAllBranchesUseCase @Inject constructor(
|
||||||
|
private val handleTransportUseCase: HandleTransportUseCase,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(git: Git) = withContext(Dispatchers.IO) {
|
||||||
|
val remotes = git.remoteList().call()
|
||||||
|
|
||||||
|
for (remote in remotes) {
|
||||||
|
git.fetch()
|
||||||
|
.setRemote(remote.name)
|
||||||
|
.setRefSpecs(remote.fetchRefSpecs)
|
||||||
|
.setTransportConfigCallback { handleTransportUseCase(it) }
|
||||||
|
.setCredentialsProvider(CredentialsProvider.getDefault())
|
||||||
|
.call()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import app.credentials.GSessionManager
|
||||||
|
import app.credentials.HttpCredentialsProvider
|
||||||
|
import org.eclipse.jgit.transport.HttpTransport
|
||||||
|
import org.eclipse.jgit.transport.SshTransport
|
||||||
|
import org.eclipse.jgit.transport.Transport
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class HandleTransportUseCase @Inject constructor(
|
||||||
|
private val sessionManager: GSessionManager
|
||||||
|
) {
|
||||||
|
operator fun invoke(transport: Transport?) {
|
||||||
|
if (transport is SshTransport) {
|
||||||
|
transport.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
||||||
|
} else if (transport is HttpTransport) {
|
||||||
|
transport.credentialsProvider = HttpCredentialsProvider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.api.RebaseResult
|
||||||
|
import org.eclipse.jgit.transport.CredentialsProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PullBranchUseCase @Inject constructor(
|
||||||
|
private val handleTransportUseCase: HandleTransportUseCase,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(git: Git, rebase: Boolean) = withContext(Dispatchers.IO) {
|
||||||
|
val pullResult = git
|
||||||
|
.pull()
|
||||||
|
.setTransportConfigCallback { handleTransportUseCase(it) }
|
||||||
|
.setRebase(rebase)
|
||||||
|
.setCredentialsProvider(CredentialsProvider.getDefault())
|
||||||
|
.call()
|
||||||
|
|
||||||
|
if (!pullResult.isSuccessful) {
|
||||||
|
var message = "Pull failed"
|
||||||
|
|
||||||
|
if (rebase) {
|
||||||
|
message = when (pullResult.rebaseResult.status) {
|
||||||
|
RebaseResult.Status.UNCOMMITTED_CHANGES -> "The pull with rebase has failed because you have got uncommited changes"
|
||||||
|
RebaseResult.Status.CONFLICTS -> "Pull with rebase has conflicts, fix them to continue"
|
||||||
|
else -> message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import app.extensions.remoteName
|
||||||
|
import app.extensions.simpleName
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.api.RebaseResult
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import org.eclipse.jgit.transport.CredentialsProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PullFromSpecificBranchUseCase @Inject constructor(
|
||||||
|
private val handleTransportUseCase: HandleTransportUseCase,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(git: Git, rebase: Boolean, remoteBranch: Ref) = withContext(Dispatchers.IO) {
|
||||||
|
val pullResult = git
|
||||||
|
.pull()
|
||||||
|
.setTransportConfigCallback { handleTransportUseCase(it) }
|
||||||
|
.setRemote(remoteBranch.remoteName)
|
||||||
|
.setRemoteBranchName(remoteBranch.simpleName)
|
||||||
|
.setRebase(rebase)
|
||||||
|
.setCredentialsProvider(CredentialsProvider.getDefault())
|
||||||
|
.call()
|
||||||
|
|
||||||
|
if (!pullResult.isSuccessful) {
|
||||||
|
var message = "Pull failed" // TODO Remove messages from here and pass the result to a custom exception type
|
||||||
|
|
||||||
|
if (rebase) {
|
||||||
|
message = when (pullResult.rebaseResult.status) {
|
||||||
|
RebaseResult.Status.UNCOMMITTED_CHANGES -> "The pull with rebase has failed because you have got uncommited changes"
|
||||||
|
RebaseResult.Status.CONFLICTS -> "Pull with rebase has conflicts, fix them to continue"
|
||||||
|
else -> message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import app.git.isRejected
|
||||||
|
import app.git.statusMessage
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.transport.RefSpec
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PushBranchUseCase @Inject constructor(
|
||||||
|
private val handleTransportUseCase: HandleTransportUseCase,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(git: Git, force: Boolean, pushTags: Boolean) = withContext(Dispatchers.IO) {
|
||||||
|
val currentBranchRefSpec = git.repository.fullBranch
|
||||||
|
|
||||||
|
val pushResult = git
|
||||||
|
.push()
|
||||||
|
.setRefSpecs(RefSpec(currentBranchRefSpec))
|
||||||
|
.setForce(force)
|
||||||
|
.apply {
|
||||||
|
if (pushTags)
|
||||||
|
setPushTags()
|
||||||
|
}
|
||||||
|
.setTransportConfigCallback { handleTransportUseCase(it) }
|
||||||
|
.call()
|
||||||
|
|
||||||
|
val results =
|
||||||
|
pushResult.map { it.remoteUpdates.filter { remoteRefUpdate -> remoteRefUpdate.status.isRejected } }
|
||||||
|
.flatten()
|
||||||
|
if (results.isNotEmpty()) {
|
||||||
|
val error = StringBuilder()
|
||||||
|
|
||||||
|
results.forEach { result ->
|
||||||
|
error.append(result.statusMessage)
|
||||||
|
error.append("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(error.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package app.git.remote_operations
|
||||||
|
|
||||||
|
import app.extensions.remoteName
|
||||||
|
import app.extensions.simpleName
|
||||||
|
import app.git.isRejected
|
||||||
|
import app.git.statusMessage
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import org.eclipse.jgit.transport.RefSpec
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PushToSpecificBranchUseCase @Inject constructor(
|
||||||
|
private val handleTransportUseCase: HandleTransportUseCase,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(git: Git, force: Boolean, pushTags: Boolean, remoteBranch: Ref) =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val currentBranchRefSpec = git.repository.fullBranch
|
||||||
|
|
||||||
|
val pushResult = git
|
||||||
|
.push()
|
||||||
|
.setRefSpecs(RefSpec("$currentBranchRefSpec:${remoteBranch.simpleName}"))
|
||||||
|
.setRemote(remoteBranch.remoteName)
|
||||||
|
.setForce(force)
|
||||||
|
.apply {
|
||||||
|
if (pushTags)
|
||||||
|
setPushTags()
|
||||||
|
}
|
||||||
|
.setTransportConfigCallback { handleTransportUseCase(it) }
|
||||||
|
.call()
|
||||||
|
|
||||||
|
val results =
|
||||||
|
pushResult.map { it.remoteUpdates.filter { remoteRefUpdate -> remoteRefUpdate.status.isRejected } }
|
||||||
|
.flatten()
|
||||||
|
if (results.isNotEmpty()) {
|
||||||
|
val error = StringBuilder()
|
||||||
|
|
||||||
|
results.forEach { result ->
|
||||||
|
error.append(result.statusMessage)
|
||||||
|
error.append("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(error.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
package app.viewmodels
|
package app.viewmodels
|
||||||
|
|
||||||
import app.extensions.nullIfEmpty
|
import app.extensions.nullIfEmpty
|
||||||
import app.git.AuthorManager
|
|
||||||
import app.git.RefreshType
|
import app.git.RefreshType
|
||||||
import app.git.TabState
|
import app.git.TabState
|
||||||
|
import app.git.author.LoadAuthorUseCase
|
||||||
|
import app.git.author.SaveAuthorUseCase
|
||||||
import app.models.AuthorInfo
|
import app.models.AuthorInfo
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@ -11,7 +12,8 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class AuthorViewModel @Inject constructor(
|
class AuthorViewModel @Inject constructor(
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val authorManager: AuthorManager,
|
private val saveAuthorUseCase: SaveAuthorUseCase,
|
||||||
|
private val loadAuthorUseCase: LoadAuthorUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val _authorInfo = MutableStateFlow(AuthorInfo(null, null, null, null))
|
private val _authorInfo = MutableStateFlow(AuthorInfo(null, null, null, null))
|
||||||
@ -21,7 +23,7 @@ class AuthorViewModel @Inject constructor(
|
|||||||
refreshType = RefreshType.NONE,
|
refreshType = RefreshType.NONE,
|
||||||
showError = true,
|
showError = true,
|
||||||
) { git ->
|
) { git ->
|
||||||
_authorInfo.value = authorManager.loadAuthor(git)
|
_authorInfo.value = loadAuthorUseCase(git)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveAuthorInfo(globalName: String, globalEmail: String, name: String, email: String) = tabState.runOperation(
|
fun saveAuthorInfo(globalName: String, globalEmail: String, name: String, email: String) = tabState.runOperation(
|
||||||
@ -35,6 +37,6 @@ class AuthorViewModel @Inject constructor(
|
|||||||
email.nullIfEmpty,
|
email.nullIfEmpty,
|
||||||
)
|
)
|
||||||
|
|
||||||
authorManager.saveAuthorInfo(git, newAuthorInfo)
|
saveAuthorUseCase(git, newAuthorInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package app.viewmodels
|
package app.viewmodels
|
||||||
|
|
||||||
import app.git.*
|
import app.git.*
|
||||||
|
import app.git.branches.*
|
||||||
|
import app.git.remote_operations.PullFromSpecificBranchUseCase
|
||||||
|
import app.git.remote_operations.PushToSpecificBranchUseCase
|
||||||
import app.preferences.AppSettings
|
import app.preferences.AppSettings
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@ -9,12 +12,17 @@ import org.eclipse.jgit.lib.Ref
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class BranchesViewModel @Inject constructor(
|
class BranchesViewModel @Inject constructor(
|
||||||
private val branchesManager: BranchesManager,
|
|
||||||
private val rebaseManager: RebaseManager,
|
private val rebaseManager: RebaseManager,
|
||||||
private val mergeManager: MergeManager,
|
private val mergeManager: MergeManager,
|
||||||
private val remoteOperationsManager: RemoteOperationsManager,
|
private val pushToSpecificBranchUseCase: PushToSpecificBranchUseCase,
|
||||||
|
private val pullFromSpecificBranchUseCase: PullFromSpecificBranchUseCase,
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val appSettings: AppSettings,
|
private val appSettings: AppSettings,
|
||||||
|
private val getCurrentBranchUseCase: GetCurrentBranchUseCase,
|
||||||
|
private val getBranchesUseCase: GetBranchesUseCase,
|
||||||
|
private val createBranchUseCase: CreateBranchUseCase,
|
||||||
|
private val deleteBranchUseCase: DeleteBranchUseCase,
|
||||||
|
private val checkoutRefUseCase: CheckoutRefUseCase,
|
||||||
) : ExpandableViewModel(true) {
|
) : ExpandableViewModel(true) {
|
||||||
private val _branches = MutableStateFlow<List<Ref>>(listOf())
|
private val _branches = MutableStateFlow<List<Ref>>(listOf())
|
||||||
val branches: StateFlow<List<Ref>>
|
val branches: StateFlow<List<Ref>>
|
||||||
@ -25,9 +33,9 @@ class BranchesViewModel @Inject constructor(
|
|||||||
get() = _currentBranch
|
get() = _currentBranch
|
||||||
|
|
||||||
suspend fun loadBranches(git: Git) {
|
suspend fun loadBranches(git: Git) {
|
||||||
_currentBranch.value = branchesManager.currentBranchRef(git)
|
_currentBranch.value = getCurrentBranchUseCase(git)
|
||||||
|
|
||||||
val branchesList = branchesManager.getBranches(git)
|
val branchesList = getBranchesUseCase(git).toMutableList()
|
||||||
|
|
||||||
// set selected branch as the first one always
|
// set selected branch as the first one always
|
||||||
val selectedBranch = branchesList.find { it.name == _currentBranch.value?.name }
|
val selectedBranch = branchesList.find { it.name == _currentBranch.value?.name }
|
||||||
@ -44,7 +52,7 @@ class BranchesViewModel @Inject constructor(
|
|||||||
refreshType = RefreshType.ONLY_LOG,
|
refreshType = RefreshType.ONLY_LOG,
|
||||||
refreshEvenIfCrashes = true,
|
refreshEvenIfCrashes = true,
|
||||||
) { git ->
|
) { git ->
|
||||||
branchesManager.createBranch(git, branchName)
|
createBranchUseCase(git, branchName)
|
||||||
this.loadBranches(git)
|
this.loadBranches(git)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,13 +65,13 @@ class BranchesViewModel @Inject constructor(
|
|||||||
fun deleteBranch(branch: Ref) = tabState.safeProcessing(
|
fun deleteBranch(branch: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
branchesManager.deleteBranch(git, branch)
|
deleteBranchUseCase(git, branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkoutRef(ref: Ref) = tabState.safeProcessing(
|
fun checkoutRef(ref: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
branchesManager.checkoutRef(git, ref)
|
checkoutRefUseCase(git, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun refresh(git: Git) {
|
suspend fun refresh(git: Git) {
|
||||||
@ -83,7 +91,7 @@ class BranchesViewModel @Inject constructor(
|
|||||||
fun pushToRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
fun pushToRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.pushToBranch(
|
pushToSpecificBranchUseCase(
|
||||||
git = git,
|
git = git,
|
||||||
force = false,
|
force = false,
|
||||||
pushTags = false,
|
pushTags = false,
|
||||||
@ -94,7 +102,7 @@ class BranchesViewModel @Inject constructor(
|
|||||||
fun pullFromRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
fun pullFromRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.pullFromBranch(
|
pullFromSpecificBranchUseCase(
|
||||||
git = git,
|
git = git,
|
||||||
rebase = false,
|
rebase = false,
|
||||||
remoteBranch = branch,
|
remoteBranch = branch,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package app.viewmodels
|
package app.viewmodels
|
||||||
|
|
||||||
import app.git.CloneStatus
|
import app.git.CloneStatus
|
||||||
import app.git.RemoteOperationsManager
|
|
||||||
import app.git.TabState
|
import app.git.TabState
|
||||||
|
import app.git.remote_operations.CloneRepositoryUseCase
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@ -14,7 +14,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class CloneViewModel @Inject constructor(
|
class CloneViewModel @Inject constructor(
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val remoteOperationsManager: RemoteOperationsManager,
|
private val cloneRepositoryUseCase: CloneRepositoryUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val _cloneStatus = MutableStateFlow<CloneStatus>(CloneStatus.None)
|
private val _cloneStatus = MutableStateFlow<CloneStatus>(CloneStatus.None)
|
||||||
@ -69,7 +69,7 @@ class CloneViewModel @Inject constructor(
|
|||||||
repoDir.mkdir()
|
repoDir.mkdir()
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteOperationsManager.clone(repoDir, url)
|
cloneRepositoryUseCase(repoDir, url)
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.collect { newCloneStatus ->
|
.collect { newCloneStatus ->
|
||||||
_cloneStatus.value = newCloneStatus
|
_cloneStatus.value = newCloneStatus
|
||||||
|
@ -4,8 +4,12 @@ import androidx.compose.foundation.ScrollState
|
|||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import app.extensions.delayedStateChange
|
import app.extensions.delayedStateChange
|
||||||
import app.git.*
|
import app.git.*
|
||||||
|
import app.git.branches.*
|
||||||
import app.git.graph.GraphCommitList
|
import app.git.graph.GraphCommitList
|
||||||
import app.git.graph.GraphNode
|
import app.git.graph.GraphNode
|
||||||
|
import app.git.remote_operations.DeleteRemoteBranchUseCase
|
||||||
|
import app.git.remote_operations.PullFromSpecificBranchUseCase
|
||||||
|
import app.git.remote_operations.PushToSpecificBranchUseCase
|
||||||
import app.preferences.AppSettings
|
import app.preferences.AppSettings
|
||||||
import app.ui.SelectedItem
|
import app.ui.SelectedItem
|
||||||
import app.ui.log.LogDialog
|
import app.ui.log.LogDialog
|
||||||
@ -34,11 +38,16 @@ private const val LOG_MIN_TIME_IN_MS_TO_SHOW_LOAD = 500L
|
|||||||
class LogViewModel @Inject constructor(
|
class LogViewModel @Inject constructor(
|
||||||
private val logManager: LogManager,
|
private val logManager: LogManager,
|
||||||
private val statusManager: StatusManager,
|
private val statusManager: StatusManager,
|
||||||
private val branchesManager: BranchesManager,
|
private val getCurrentBranchUseCase: GetCurrentBranchUseCase,
|
||||||
|
private val checkoutRefUseCase: CheckoutRefUseCase,
|
||||||
|
private val createBranchOnCommitUseCase: CreateBranchOnCommitUseCase,
|
||||||
|
private val deleteBranchUseCase: DeleteBranchUseCase,
|
||||||
|
private val pushToSpecificBranchUseCase: PushToSpecificBranchUseCase,
|
||||||
|
private val pullFromSpecificBranchUseCase: PullFromSpecificBranchUseCase,
|
||||||
|
private val deleteRemoteBranchUseCase: DeleteRemoteBranchUseCase,
|
||||||
private val rebaseManager: RebaseManager,
|
private val rebaseManager: RebaseManager,
|
||||||
private val tagsManager: TagsManager,
|
private val tagsManager: TagsManager,
|
||||||
private val mergeManager: MergeManager,
|
private val mergeManager: MergeManager,
|
||||||
private val remoteOperationsManager: RemoteOperationsManager,
|
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val appSettings: AppSettings,
|
private val appSettings: AppSettings,
|
||||||
) {
|
) {
|
||||||
@ -83,7 +92,7 @@ class LogViewModel @Inject constructor(
|
|||||||
_logStatus.value = LogStatus.Loading
|
_logStatus.value = LogStatus.Loading
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
val currentBranch = branchesManager.currentBranchRef(git)
|
val currentBranch = getCurrentBranchUseCase(git)
|
||||||
|
|
||||||
val statusSummary = statusManager.getStatusSummary(
|
val statusSummary = statusManager.getStatusSummary(
|
||||||
git = git,
|
git = git,
|
||||||
@ -113,7 +122,7 @@ class LogViewModel @Inject constructor(
|
|||||||
fun pushToRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
fun pushToRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.pushToBranch(
|
pushToSpecificBranchUseCase(
|
||||||
git = git,
|
git = git,
|
||||||
force = false,
|
force = false,
|
||||||
pushTags = false,
|
pushTags = false,
|
||||||
@ -124,7 +133,7 @@ class LogViewModel @Inject constructor(
|
|||||||
fun pullFromRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
fun pullFromRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.pullFromBranch(
|
pullFromSpecificBranchUseCase(
|
||||||
git = git,
|
git = git,
|
||||||
rebase = false,
|
rebase = false,
|
||||||
remoteBranch = branch,
|
remoteBranch = branch,
|
||||||
@ -152,7 +161,7 @@ class LogViewModel @Inject constructor(
|
|||||||
fun checkoutRef(ref: Ref) = tabState.safeProcessing(
|
fun checkoutRef(ref: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
branchesManager.checkoutRef(git, ref)
|
checkoutRefUseCase(git, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cherrypickCommit(revCommit: RevCommit) = tabState.safeProcessing(
|
fun cherrypickCommit(revCommit: RevCommit) = tabState.safeProcessing(
|
||||||
@ -164,7 +173,7 @@ class LogViewModel @Inject constructor(
|
|||||||
fun createBranchOnCommit(branch: String, revCommit: RevCommit) = tabState.safeProcessing(
|
fun createBranchOnCommit(branch: String, revCommit: RevCommit) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
branchesManager.createBranchOnCommit(git, branch, revCommit)
|
createBranchOnCommitUseCase(git, branch, revCommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTagOnCommit(tag: String, revCommit: RevCommit) = tabState.safeProcessing(
|
fun createTagOnCommit(tag: String, revCommit: RevCommit) = tabState.safeProcessing(
|
||||||
@ -182,7 +191,7 @@ class LogViewModel @Inject constructor(
|
|||||||
fun deleteBranch(branch: Ref) = tabState.safeProcessing(
|
fun deleteBranch(branch: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
branchesManager.deleteBranch(git, branch)
|
deleteBranchUseCase(git, branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteTag(tag: Ref) = tabState.safeProcessing(
|
fun deleteTag(tag: Ref) = tabState.safeProcessing(
|
||||||
@ -196,7 +205,7 @@ class LogViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun uncommitedChangesLoadLog(git: Git) {
|
private suspend fun uncommitedChangesLoadLog(git: Git) {
|
||||||
val currentBranch = branchesManager.currentBranchRef(git)
|
val currentBranch = getCurrentBranchUseCase(git)
|
||||||
val hasUncommitedChanges = statusManager.hasUncommitedChanges(git)
|
val hasUncommitedChanges = statusManager.hasUncommitedChanges(git)
|
||||||
|
|
||||||
val statsSummary = if (hasUncommitedChanges) {
|
val statsSummary = if (hasUncommitedChanges) {
|
||||||
@ -357,7 +366,7 @@ class LogViewModel @Inject constructor(
|
|||||||
fun deleteRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
fun deleteRemoteBranch(branch: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.deleteBranch(git, branch)
|
deleteRemoteBranchUseCase(git, branch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
package app.viewmodels
|
package app.viewmodels
|
||||||
|
|
||||||
import app.git.*
|
import app.git.*
|
||||||
|
import app.git.remote_operations.DeleteRemoteBranchUseCase
|
||||||
|
import app.git.remote_operations.FetchAllBranchesUseCase
|
||||||
|
import app.git.remote_operations.PullBranchUseCase
|
||||||
|
import app.git.remote_operations.PushBranchUseCase
|
||||||
import java.awt.Desktop
|
import java.awt.Desktop
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MenuViewModel @Inject constructor(
|
class MenuViewModel @Inject constructor(
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val remoteOperationsManager: RemoteOperationsManager,
|
private val pullBranchUseCase: PullBranchUseCase,
|
||||||
|
private val pushBranchUseCase: PushBranchUseCase,
|
||||||
|
private val fetchAllBranchesUseCase: FetchAllBranchesUseCase,
|
||||||
private val stashManager: StashManager,
|
private val stashManager: StashManager,
|
||||||
private val statusManager: StatusManager,
|
private val statusManager: StatusManager,
|
||||||
) {
|
) {
|
||||||
@ -14,21 +20,21 @@ class MenuViewModel @Inject constructor(
|
|||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
refreshEvenIfCrashes = true,
|
refreshEvenIfCrashes = true,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.pull(git, rebase)
|
pullBranchUseCase(git, rebase)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchAll() = tabState.safeProcessing(
|
fun fetchAll() = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
refreshEvenIfCrashes = true,
|
refreshEvenIfCrashes = true,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.fetchAll(git)
|
fetchAllBranchesUseCase(git)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun push(force: Boolean = false, pushTags: Boolean = false) = tabState.safeProcessing(
|
fun push(force: Boolean = false, pushTags: Boolean = false) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
refreshEvenIfCrashes = true,
|
refreshEvenIfCrashes = true,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.push(git, force, pushTags)
|
pushBranchUseCase(git, force, pushTags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stash() = tabState.safeProcessing(
|
fun stash() = tabState.safeProcessing(
|
||||||
|
@ -2,6 +2,9 @@ package app.viewmodels
|
|||||||
|
|
||||||
import app.exceptions.InvalidRemoteUrlException
|
import app.exceptions.InvalidRemoteUrlException
|
||||||
import app.git.*
|
import app.git.*
|
||||||
|
import app.git.branches.DeleteLocallyRemoteBranches
|
||||||
|
import app.git.branches.GetRemoteBranchesUseCase
|
||||||
|
import app.git.remote_operations.DeleteRemoteBranchUseCase
|
||||||
import app.ui.dialogs.RemoteWrapper
|
import app.ui.dialogs.RemoteWrapper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@ -14,18 +17,19 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class RemotesViewModel @Inject constructor(
|
class RemotesViewModel @Inject constructor(
|
||||||
private val remotesManager: RemotesManager,
|
private val remotesManager: RemotesManager,
|
||||||
private val remoteOperationsManager: RemoteOperationsManager,
|
private val deleteRemoteBranchUseCase: DeleteRemoteBranchUseCase,
|
||||||
private val branchesManager: BranchesManager,
|
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
|
private val getRemoteBranchesUseCase: GetRemoteBranchesUseCase,
|
||||||
|
private val deleteLocallyRemoteBranchesUseCase: DeleteLocallyRemoteBranches,
|
||||||
) : ExpandableViewModel() {
|
) : ExpandableViewModel() {
|
||||||
private val _remotes = MutableStateFlow<List<RemoteView>>(listOf())
|
private val _remotes = MutableStateFlow<List<RemoteView>>(listOf())
|
||||||
val remotes: StateFlow<List<RemoteView>>
|
val remotes: StateFlow<List<RemoteView>>
|
||||||
get() = _remotes
|
get() = _remotes
|
||||||
|
|
||||||
suspend fun loadRemotes(git: Git) = withContext(Dispatchers.IO) {
|
private suspend fun loadRemotes(git: Git) = withContext(Dispatchers.IO) {
|
||||||
val remotes = git.remoteList()
|
val remotes = git.remoteList()
|
||||||
.call()
|
.call()
|
||||||
val allRemoteBranches = branchesManager.remoteBranches(git)
|
val allRemoteBranches = getRemoteBranchesUseCase(git)
|
||||||
|
|
||||||
remotesManager.loadRemotes(git, allRemoteBranches)
|
remotesManager.loadRemotes(git, allRemoteBranches)
|
||||||
val remoteInfoList = remotes.map { remoteConfig ->
|
val remoteInfoList = remotes.map { remoteConfig ->
|
||||||
@ -45,7 +49,7 @@ class RemotesViewModel @Inject constructor(
|
|||||||
fun deleteRemoteBranch(ref: Ref) = tabState.safeProcessing(
|
fun deleteRemoteBranch(ref: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
remoteOperationsManager.deleteBranch(git, ref)
|
deleteRemoteBranchUseCase(git, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun refresh(git: Git) = withContext(Dispatchers.IO) {
|
suspend fun refresh(git: Git) = withContext(Dispatchers.IO) {
|
||||||
@ -72,14 +76,14 @@ class RemotesViewModel @Inject constructor(
|
|||||||
) { git ->
|
) { git ->
|
||||||
remotesManager.deleteRemote(git, remoteName)
|
remotesManager.deleteRemote(git, remoteName)
|
||||||
|
|
||||||
val remoteBranches = branchesManager.remoteBranches(git)
|
val remoteBranches = getRemoteBranchesUseCase(git)
|
||||||
val remoteToDeleteBranchesNames = remoteBranches.filter {
|
val remoteToDeleteBranchesNames = remoteBranches.filter {
|
||||||
it.name.startsWith("refs/remotes/$remoteName/")
|
it.name.startsWith("refs/remotes/$remoteName/")
|
||||||
}.map {
|
}.map {
|
||||||
it.name
|
it.name
|
||||||
}
|
}
|
||||||
|
|
||||||
branchesManager.deleteLocallyRemoteBranches(git, remoteToDeleteBranchesNames)
|
deleteLocallyRemoteBranchesUseCase(git, remoteToDeleteBranchesNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package app.viewmodels
|
package app.viewmodels
|
||||||
|
|
||||||
import app.git.BranchesManager
|
|
||||||
import app.git.RefreshType
|
import app.git.RefreshType
|
||||||
import app.git.TabState
|
import app.git.TabState
|
||||||
import app.git.TagsManager
|
import app.git.TagsManager
|
||||||
|
import app.git.branches.CheckoutRefUseCase
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@ -14,8 +14,8 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class TagsViewModel @Inject constructor(
|
class TagsViewModel @Inject constructor(
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val branchesManager: BranchesManager,
|
|
||||||
private val tagsManager: TagsManager,
|
private val tagsManager: TagsManager,
|
||||||
|
private val checkoutRefUseCase: CheckoutRefUseCase,
|
||||||
) : ExpandableViewModel() {
|
) : ExpandableViewModel() {
|
||||||
private val _tags = MutableStateFlow<List<Ref>>(listOf())
|
private val _tags = MutableStateFlow<List<Ref>>(listOf())
|
||||||
val tags: StateFlow<List<Ref>>
|
val tags: StateFlow<List<Ref>>
|
||||||
@ -30,7 +30,7 @@ class TagsViewModel @Inject constructor(
|
|||||||
fun checkoutRef(ref: Ref) = tabState.safeProcessing(
|
fun checkoutRef(ref: Ref) = tabState.safeProcessing(
|
||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
branchesManager.checkoutRef(git, ref)
|
checkoutRefUseCase(git, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteTag(tag: Ref) = tabState.safeProcessing(
|
fun deleteTag(tag: Ref) = tabState.safeProcessing(
|
||||||
|
@ -3,6 +3,8 @@ package app.git
|
|||||||
import app.credentials.GProcess
|
import app.credentials.GProcess
|
||||||
import app.credentials.GRemoteSession
|
import app.credentials.GRemoteSession
|
||||||
import app.credentials.GSessionManager
|
import app.credentials.GSessionManager
|
||||||
|
import app.git.remote_operations.CloneRepositoryUseCase
|
||||||
|
import app.git.remote_operations.HandleTransportUseCase
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
@ -31,8 +33,8 @@ class BeforeRepoAllTestsExtension : BeforeAllCallback, AfterAllCallback {
|
|||||||
// The following line registers a callback hook when the root test context is shut down
|
// The following line registers a callback hook when the root test context is shut down
|
||||||
context.root.getStore(GLOBAL).put("gitnuro_tests", this)
|
context.root.getStore(GLOBAL).put("gitnuro_tests", this)
|
||||||
|
|
||||||
val remoteOperationsManager = RemoteOperationsManager(GSessionManager { GRemoteSession { GProcess() } })
|
val cloneRepositoryUseCase = CloneRepositoryUseCase(HandleTransportUseCase(GSessionManager { GRemoteSession { GProcess() } }))
|
||||||
remoteOperationsManager.clone(repoDir, REPO_URL)
|
cloneRepositoryUseCase(repoDir, REPO_URL)
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.collect { newCloneStatus ->
|
.collect { newCloneStatus ->
|
||||||
println("Clonning test repository: $newCloneStatus")
|
println("Clonning test repository: $newCloneStatus")
|
||||||
|
@ -1,154 +1,154 @@
|
|||||||
package app.git
|
//package app.git
|
||||||
|
//
|
||||||
import app.TestUtils.copyDir
|
//import app.TestUtils.copyDir
|
||||||
import kotlinx.coroutines.runBlocking
|
//import kotlinx.coroutines.runBlocking
|
||||||
import org.eclipse.jgit.api.Git
|
//import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.lib.ObjectId
|
//import org.eclipse.jgit.lib.ObjectId
|
||||||
import org.eclipse.jgit.lib.Repository
|
//import org.eclipse.jgit.lib.Repository
|
||||||
import org.junit.jupiter.api.AfterEach
|
//import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
//import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
//import org.junit.jupiter.api.Assertions.assertNotNull
|
||||||
import org.junit.jupiter.api.BeforeEach
|
//import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
//import org.junit.jupiter.api.extension.ExtendWith
|
||||||
import java.io.File
|
//import java.io.File
|
||||||
|
//
|
||||||
private const val DEFAULT_REMOTE = "origin"
|
//private const val DEFAULT_REMOTE = "origin"
|
||||||
private const val DEFAULT_PRIMARY_BRANCH = "main"
|
//private const val DEFAULT_PRIMARY_BRANCH = "main"
|
||||||
private const val DEFAULT_SECONDARY_BRANCH = "TestBranch1"
|
//private const val DEFAULT_SECONDARY_BRANCH = "TestBranch1"
|
||||||
|
//
|
||||||
private const val LOCAL_PREFIX = "refs/heads"
|
//private const val LOCAL_PREFIX = "refs/heads"
|
||||||
private const val DEFAULT_PRIMARY_BRANCH_FULL_NAME = "$LOCAL_PREFIX/$DEFAULT_PRIMARY_BRANCH"
|
//private const val DEFAULT_PRIMARY_BRANCH_FULL_NAME = "$LOCAL_PREFIX/$DEFAULT_PRIMARY_BRANCH"
|
||||||
private const val DEFAULT_SECONDARY_BRANCH_FULL_NAME = "$LOCAL_PREFIX/$DEFAULT_SECONDARY_BRANCH"
|
//private const val DEFAULT_SECONDARY_BRANCH_FULL_NAME = "$LOCAL_PREFIX/$DEFAULT_SECONDARY_BRANCH"
|
||||||
|
//
|
||||||
private const val INITIAL_LOCAL_BRANCH_COUNT = 1
|
//private const val INITIAL_LOCAL_BRANCH_COUNT = 1
|
||||||
private const val INITIAL_REMOTE_BRANCH_COUNT = 2
|
//private const val INITIAL_REMOTE_BRANCH_COUNT = 2
|
||||||
|
//
|
||||||
private const val REMOTE_PREFIX = "refs/remotes/$DEFAULT_REMOTE"
|
//private const val REMOTE_PREFIX = "refs/remotes/$DEFAULT_REMOTE"
|
||||||
|
//
|
||||||
private val initialRemoteBranches = listOf(
|
//private val initialRemoteBranches = listOf(
|
||||||
"$REMOTE_PREFIX/$DEFAULT_PRIMARY_BRANCH",
|
// "$REMOTE_PREFIX/$DEFAULT_PRIMARY_BRANCH",
|
||||||
"$REMOTE_PREFIX/$DEFAULT_SECONDARY_BRANCH",
|
// "$REMOTE_PREFIX/$DEFAULT_SECONDARY_BRANCH",
|
||||||
)
|
//)
|
||||||
|
//
|
||||||
@ExtendWith(BeforeRepoAllTestsExtension::class)
|
//@ExtendWith(BeforeRepoAllTestsExtension::class)
|
||||||
class BranchesManagerTest {
|
//class BranchesManagerTest {
|
||||||
private lateinit var repo: Repository
|
// private lateinit var repo: Repository
|
||||||
private lateinit var git: Git
|
// private lateinit var git: Git
|
||||||
private lateinit var branchesManagerTestDir: File
|
// private lateinit var branchesManagerTestDir: File
|
||||||
private val branchesManager = BranchesManager()
|
// private val branchesManager = BranchesManager()
|
||||||
|
//
|
||||||
@BeforeEach
|
// @BeforeEach
|
||||||
fun setUp() {
|
// fun setUp() {
|
||||||
branchesManagerTestDir = File(tempDir, "branches_manager")
|
// branchesManagerTestDir = File(tempDir, "branches_manager")
|
||||||
branchesManagerTestDir.mkdir()
|
// branchesManagerTestDir.mkdir()
|
||||||
|
//
|
||||||
copyDir(repoDir.absolutePath, branchesManagerTestDir.absolutePath)
|
// copyDir(repoDir.absolutePath, branchesManagerTestDir.absolutePath)
|
||||||
|
//
|
||||||
repo = RepositoryManager().openRepository(branchesManagerTestDir)
|
// repo = RepositoryManager().openRepository(branchesManagerTestDir)
|
||||||
git = Git(repo)
|
// git = Git(repo)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@AfterEach
|
// @AfterEach
|
||||||
fun tearDown() {
|
// fun tearDown() {
|
||||||
repo.close()
|
// repo.close()
|
||||||
branchesManagerTestDir.deleteRecursively()
|
// branchesManagerTestDir.deleteRecursively()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun currentBranchRef() = runBlocking {
|
// fun currentBranchRef() = runBlocking {
|
||||||
val currentBranchRef = branchesManager.currentBranchRef(Git(repo))
|
// val currentBranchRef = branchesManager.currentBranchRef(Git(repo))
|
||||||
assertEquals(currentBranchRef?.name, "refs/heads/$DEFAULT_PRIMARY_BRANCH")
|
// assertEquals(currentBranchRef?.name, "refs/heads/$DEFAULT_PRIMARY_BRANCH")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun getBranches() = runBlocking {
|
// fun getBranches() = runBlocking {
|
||||||
val branchesManager = BranchesManager()
|
// val branchesManager = BranchesManager()
|
||||||
val branches = branchesManager.getBranches(git)
|
// val branches = branchesManager.getBranches(git)
|
||||||
assertEquals(branches.count(), INITIAL_LOCAL_BRANCH_COUNT)
|
// assertEquals(branches.count(), INITIAL_LOCAL_BRANCH_COUNT)
|
||||||
val containsMain = branches.any { it.name == "refs/heads/$DEFAULT_PRIMARY_BRANCH" }
|
// val containsMain = branches.any { it.name == "refs/heads/$DEFAULT_PRIMARY_BRANCH" }
|
||||||
assert(containsMain) { println("Error: Branch main does not exist") }
|
// assert(containsMain) { println("Error: Branch main does not exist") }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun checkoutRef() = runBlocking {
|
// fun checkoutRef() = runBlocking {
|
||||||
val remoteBranchToCheckout = "$REMOTE_PREFIX/$DEFAULT_SECONDARY_BRANCH"
|
// val remoteBranchToCheckout = "$REMOTE_PREFIX/$DEFAULT_SECONDARY_BRANCH"
|
||||||
|
//
|
||||||
var currentBranch = branchesManager.currentBranchRef(git)
|
// var currentBranch = branchesManager.currentBranchRef(git)
|
||||||
assertEquals(currentBranch?.name, DEFAULT_PRIMARY_BRANCH_FULL_NAME)
|
// assertEquals(currentBranch?.name, DEFAULT_PRIMARY_BRANCH_FULL_NAME)
|
||||||
|
//
|
||||||
// Checkout a remote branch
|
// // Checkout a remote branch
|
||||||
var branchToCheckout = branchesManager.remoteBranches(git).first { it.name == remoteBranchToCheckout }
|
// var branchToCheckout = branchesManager.remoteBranches(git).first { it.name == remoteBranchToCheckout }
|
||||||
branchesManager.checkoutRef(git, branchToCheckout)
|
// branchesManager.checkoutRef(git, branchToCheckout)
|
||||||
|
//
|
||||||
currentBranch = branchesManager.currentBranchRef(git)
|
// currentBranch = branchesManager.currentBranchRef(git)
|
||||||
assertEquals(DEFAULT_SECONDARY_BRANCH_FULL_NAME, currentBranch?.name)
|
// assertEquals(DEFAULT_SECONDARY_BRANCH_FULL_NAME, currentBranch?.name)
|
||||||
|
//
|
||||||
// Checkout a local branch
|
// // Checkout a local branch
|
||||||
branchToCheckout = branchesManager.getBranches(git).first { it.name == DEFAULT_PRIMARY_BRANCH_FULL_NAME }
|
// branchToCheckout = branchesManager.getBranches(git).first { it.name == DEFAULT_PRIMARY_BRANCH_FULL_NAME }
|
||||||
branchesManager.checkoutRef(git, branchToCheckout)
|
// branchesManager.checkoutRef(git, branchToCheckout)
|
||||||
currentBranch = branchesManager.currentBranchRef(git)
|
// currentBranch = branchesManager.currentBranchRef(git)
|
||||||
|
//
|
||||||
assertEquals(DEFAULT_PRIMARY_BRANCH_FULL_NAME, currentBranch?.name)
|
// assertEquals(DEFAULT_PRIMARY_BRANCH_FULL_NAME, currentBranch?.name)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun createBranch() = runBlocking {
|
// fun createBranch() = runBlocking {
|
||||||
val branchName = "test"
|
// val branchName = "test"
|
||||||
branchesManager.createBranch(git, branchName)
|
// branchesManager.createBranch(git, branchName)
|
||||||
|
//
|
||||||
val branches = branchesManager.getBranches(git)
|
// val branches = branchesManager.getBranches(git)
|
||||||
assertEquals(INITIAL_LOCAL_BRANCH_COUNT + 1, branches.count())
|
// assertEquals(INITIAL_LOCAL_BRANCH_COUNT + 1, branches.count())
|
||||||
val containsNewBranch = branches.any { it.name == "refs/heads/$branchName" }
|
// val containsNewBranch = branches.any { it.name == "refs/heads/$branchName" }
|
||||||
|
//
|
||||||
assert(containsNewBranch) { println("Error: Branch $branchName does not exist") }
|
// assert(containsNewBranch) { println("Error: Branch $branchName does not exist") }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun createBranchOnCommit() = runBlocking {
|
// fun createBranchOnCommit() = runBlocking {
|
||||||
val branchName = "test"
|
// val branchName = "test"
|
||||||
val commitId = "f66757e23dc5c43eccbe84d02c58245406c8f8f4"
|
// val commitId = "f66757e23dc5c43eccbe84d02c58245406c8f8f4"
|
||||||
|
//
|
||||||
val objectId = ObjectId.fromString(commitId)
|
// val objectId = ObjectId.fromString(commitId)
|
||||||
val revCommit = repo.parseCommit(objectId)
|
// val revCommit = repo.parseCommit(objectId)
|
||||||
branchesManager.createBranchOnCommit(git, branchName, revCommit)
|
// branchesManager.createBranchOnCommit(git, branchName, revCommit)
|
||||||
|
//
|
||||||
val branches = branchesManager.getBranches(git)
|
// val branches = branchesManager.getBranches(git)
|
||||||
assertEquals(INITIAL_LOCAL_BRANCH_COUNT + 1, branches.count())
|
// assertEquals(INITIAL_LOCAL_BRANCH_COUNT + 1, branches.count())
|
||||||
val newBranch = branches.firstOrNull { it.name == "refs/heads/$branchName" }
|
// val newBranch = branches.firstOrNull { it.name == "refs/heads/$branchName" }
|
||||||
|
//
|
||||||
assertNotNull(newBranch)
|
// assertNotNull(newBranch)
|
||||||
assertEquals(commitId, newBranch?.objectId?.name())
|
// assertEquals(commitId, newBranch?.objectId?.name())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun deleteBranch() = runBlocking {
|
// fun deleteBranch() = runBlocking {
|
||||||
val branchToDeleteName = "branch_to_delete"
|
// val branchToDeleteName = "branch_to_delete"
|
||||||
val currentBranch = branchesManager.currentBranchRef(git) // should be "main"
|
// val currentBranch = branchesManager.currentBranchRef(git) // should be "main"
|
||||||
assertNotNull(currentBranch)
|
// assertNotNull(currentBranch)
|
||||||
|
//
|
||||||
val newBranch = branchesManager.createBranch(git, branchToDeleteName)
|
// val newBranch = branchesManager.createBranch(git, branchToDeleteName)
|
||||||
branchesManager.checkoutRef(git, currentBranch!!)
|
// branchesManager.checkoutRef(git, currentBranch!!)
|
||||||
|
//
|
||||||
branchesManager.deleteBranch(git, newBranch)
|
// branchesManager.deleteBranch(git, newBranch)
|
||||||
|
//
|
||||||
val branches = branchesManager.getBranches(git)
|
// val branches = branchesManager.getBranches(git)
|
||||||
assertEquals(INITIAL_LOCAL_BRANCH_COUNT, branches.count())
|
// assertEquals(INITIAL_LOCAL_BRANCH_COUNT, branches.count())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun remoteBranches() = runBlocking {
|
// fun remoteBranches() = runBlocking {
|
||||||
val remoteBranches = branchesManager.remoteBranches(git)
|
// val remoteBranches = branchesManager.remoteBranches(git)
|
||||||
assertEquals(remoteBranches.count(), INITIAL_REMOTE_BRANCH_COUNT)
|
// assertEquals(remoteBranches.count(), INITIAL_REMOTE_BRANCH_COUNT)
|
||||||
remoteBranches.forEach { ref ->
|
// remoteBranches.forEach { ref ->
|
||||||
assert(initialRemoteBranches.contains(ref.name))
|
// assert(initialRemoteBranches.contains(ref.name))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@org.junit.jupiter.api.Test
|
// @org.junit.jupiter.api.Test
|
||||||
fun deleteLocallyRemoteBranches() = runBlocking {
|
// fun deleteLocallyRemoteBranches() = runBlocking {
|
||||||
branchesManager.deleteLocallyRemoteBranches(git, initialRemoteBranches)
|
// branchesManager.deleteLocallyRemoteBranches(git, initialRemoteBranches)
|
||||||
|
//
|
||||||
val branches = branchesManager.remoteBranches(git)
|
// val branches = branchesManager.remoteBranches(git)
|
||||||
assertEquals(0, branches.count())
|
// assertEquals(0, branches.count())
|
||||||
}
|
// }
|
||||||
}
|
//}
|
Loading…
Reference in New Issue
Block a user