commit - f4f674a37c137f1977cd8043a8a05de6752f9277
commit + 72c6ec218af4da0b1abb8c7740c3e1fd3e9e1eef
blob - 1b85568799abb3fcbf7961aefcb27025bd1c4fc0
blob + 6a0bb32c7e8d756c4961baa329c7d45ae1176ee9
--- src/main/kotlin/dev/nezzontli/gotvcs/GotVcs.kt
+++ src/main/kotlin/dev/nezzontli/gotvcs/GotVcs.kt
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
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<out Change>, 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 <path>` 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<FilePath> = (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
}
}