commit 72c6ec218af4da0b1abb8c7740c3e1fd3e9e1eef from: ale date: Fri Jul 24 09:32:42 2026 UTC Simplify `GotCommitAndSendExecutor` by delegating commit handling to `CommitContext` and removing redundant logic commit - f4f674a37c137f1977cd8043a8a05de6752f9277 commit + 72c6ec218af4da0b1abb8c7740c3e1fd3e9e1eef blob - 1b85568799abb3fcbf7961aefcb27025bd1c4fc0 blob + 6a0bb32c7e8d756c4961baa329c7d45ae1176ee9 --- src/main/kotlin/dev/nezzontli/gotvcs/GotVcs.kt +++ src/main/kotlin/dev/nezzontli/gotvcs/GotVcs.kt @@ -29,7 +29,7 @@ class GotVcs(project: Project) : AbstractVcs(project, private val rollbackEnvironment = GotRollbackEnvironment(project, commandLine) private val historyProvider = GotVcsHistoryProvider(project, commandLine) private val updateEnvironment = GotUpdateEnvironment(commandLine) - private val commitAndSendExecutor = GotCommitAndSendExecutor(project, checkinEnvironment) + private val commitAndSendExecutor = GotCommitAndSendExecutor() override fun getDisplayName(): String = NAME blob - 00dd2062abec9b198fe10c55daef4490c8bc8ce1 blob + 5c092520c9796da978ad16911533733ced67cccc --- src/main/kotlin/dev/nezzontli/gotvcs/checkin/GotCommitAndSendExecutor.kt +++ src/main/kotlin/dev/nezzontli/gotvcs/checkin/GotCommitAndSendExecutor.kt @@ -1,114 +1,33 @@ package dev.nezzontli.gotvcs.checkin -import com.intellij.notification.NotificationGroupManager -import com.intellij.notification.NotificationType -import com.intellij.openapi.actionSystem.ActionManager -import com.intellij.openapi.actionSystem.ActionUiKind -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.Presentation -import com.intellij.openapi.actionSystem.ex.ActionUtil -import com.intellij.openapi.actionSystem.impl.SimpleDataContext -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.vcs.FilePath -import com.intellij.openapi.vcs.ProjectLevelVcsManager -import com.intellij.openapi.vcs.changes.Change -import com.intellij.openapi.vcs.changes.ChangeListManager -import com.intellij.openapi.vcs.changes.ChangeListManagerImpl import com.intellij.openapi.vcs.changes.CommitContext import com.intellij.openapi.vcs.changes.CommitExecutor import com.intellij.openapi.vcs.changes.CommitSession -import com.intellij.vcsUtil.VcsUtil -import dev.nezzontli.gotvcs.repo.GotRepositoryManager const val COMMIT_AND_SEND_EXECUTOR_ID = "Got.Commit.And.Send" /** - * Commits exactly like the default "Commit" button (delegates to the same - * CheckinEnvironment), then opens the native Push dialog (same action as - * Ctrl+Shift+K) so the user can review and send from there. + * Mirrors Git's own "Commit and Push": rather than reimplementing the + * commit, this just flags the CommitContext and returns CommitSession + * .VCS_COMMIT, the sentinel meaning "run the normal commit" -- so the + * platform's own automatic handling of unversioned/deleted files (which a + * fully custom CommitSession does not get; verified by decompiling + * ChangesViewCommitWorkflowHandler and CommitSessionInfo.isVcsCommit()) + * still applies. GotCheckinEnvironment checks PUSH_AFTER_COMMIT_KEY once + * the commit succeeds and opens the native Push dialog from there. */ -class GotCommitAndSendExecutor( - private val project: Project, - private val checkinEnvironment: GotCheckinEnvironment, -) : CommitExecutor { +class GotCommitAndSendExecutor : CommitExecutor { override fun getActionText(): String = "Commit and Send" override fun getId(): String = COMMIT_AND_SEND_EXECUTOR_ID - override fun createCommitSession(context: CommitContext): CommitSession = session + override fun useDefaultAction(): Boolean = false - private val session = object : CommitSession { - // execute() runs on a background thread (same as the default commit - // action), but opening the Push dialog is a UI action and must - // happen on the EDT -- see com.intellij.execution.process - // .OSProcessHandler#checkEdtAndReadAction-style threading rules. - override fun execute(changes: MutableCollection, commitMessage: String?) { - val message = commitMessage.orEmpty() + override fun requiresSyncCommitChecks(): Boolean = true - // Unlike the default "Commit" button, a custom CommitExecutor's - // session does NOT get scheduleUnversionedFilesForAddition() / - // scheduleMissingFileForDeletion() called automatically by the - // platform first (verified by decompiling - // ChangesViewCommitWorkflowHandler.addUnversionedFiles(), which - // is a no-op unless CommitSessionInfo.isVcsCommit() is true) -- - // and `got commit -m msg ` errors with "no changes to - // commit" for a path that hasn't been `got add`-ed yet (verified - // directly against the CLI). So new/deleted files must be - // staged here ourselves before the actual commit. - val changeListManager = ChangeListManager.getInstance(project) as ChangeListManagerImpl - val unversionedFiles = changeListManager.unversionedFilesPaths.mapNotNull { it.virtualFile } - val deletedPaths = changeListManager.deletedFiles.map { it.path } - - if (unversionedFiles.isNotEmpty()) { - checkinEnvironment.scheduleUnversionedFilesForAddition(unversionedFiles.toMutableList()) - } - if (deletedPaths.isNotEmpty()) { - checkinEnvironment.scheduleMissingFileForDeletion(deletedPaths.toMutableList()) - } - - val trackedPaths = changes.mapNotNull { it.afterRevision?.file ?: it.beforeRevision?.file } - val unversionedFilePaths = unversionedFiles.map { VcsUtil.getFilePath(it) } - val allPaths: List = (trackedPaths + unversionedFilePaths + deletedPaths).distinct() - - val errors = checkinEnvironment.commitFilePaths(allPaths, message) - if (errors.isNotEmpty()) { - val group = NotificationGroupManager.getInstance().getNotificationGroup("got") - group.createNotification( - "got commit failed", - errors.joinToString("\n") { it.message.orEmpty() }, - NotificationType.ERROR, - ).notify(project) - return - } - - // GotRepository's cached branch/revision (used to resolve the - // Push dialog's target) is normally refreshed by the platform's - // own post-commit VCS-root-dirty machinery, but that happens - // asynchronously and can race with the dialog opening right - // below -- refreshing it here ourselves, still on this - // background thread, guarantees the dialog sees the commit that - // was just made instead of possibly-stale cached state. - val vcsManager = ProjectLevelVcsManager.getInstance(project) - val repositoryManager = project.getService(GotRepositoryManager::class.java) - val affectedRoots = allPaths.mapNotNull { vcsManager.getVcsRootFor(it) }.toSet() - for (root in affectedRoots) { - repositoryManager.getRepositoryForRoot(root)?.update() - } - - ApplicationManager.getApplication().invokeLater { - val pushAction = ActionManager.getInstance().getAction("Vcs.Push") ?: return@invokeLater - val dataContext = SimpleDataContext.getProjectContext(project) - val event = AnActionEvent.createEvent( - dataContext, - Presentation(), - "GotCommitAndSend", - ActionUiKind.NONE, - null, - ) - ActionUtil.performAction(pushAction, event) - } - } + override fun createCommitSession(context: CommitContext): CommitSession { + context.putUserData(PUSH_AFTER_COMMIT_KEY, true) + return CommitSession.VCS_COMMIT } }