diff --git a/Classes/Feature/WorkspaceCommandHandler.php b/Classes/Feature/WorkspaceCommandHandler.php index 00911a7..b499fbe 100644 --- a/Classes/Feature/WorkspaceCommandHandler.php +++ b/Classes/Feature/WorkspaceCommandHandler.php @@ -51,6 +51,7 @@ use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Command\RebaseWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Dto\RebaseErrorHandlingStrategy; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Event\WorkspaceWasRebased; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\PartialWorkspaceRebaseFailed; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\WorkspaceRebaseFailed; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamAlreadyExists; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; @@ -505,8 +506,14 @@ static function ($handle) use ($commandSimulator, $matchingCommands, $remainingC yield $this->reopenContentStreamWithoutConstraintChecks( $workspace->currentContentStreamId ); - - throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getConflictingEvents()); + match ($workspace->status) { + // If the workspace is up-to-date it must be a problem regarding that the order of events cannot be changed + WorkspaceStatus::UP_TO_DATE => + throw PartialWorkspaceRebaseFailed::duringPartialPublish($commandSimulator->getConflictingEvents()), + // If the workspace is outdated we cannot know for sure but suspect that the conflict arose due to changes in the base workspace. + WorkspaceStatus::OUTDATED => + throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getConflictingEvents()) + }; } // this could empty and a no-op for the rare case when a command returns empty events e.g. the node was already tagged with this subtree tag @@ -605,7 +612,6 @@ private function handleDiscardIndividualNodesFromWorkspace( // quick path everything was discarded yield from $this->discardWorkspace( $workspace, - $workspaceContentStreamVersion, $baseWorkspace, $baseWorkspaceContentStreamVersion, $command->newContentStreamId @@ -627,7 +633,14 @@ static function ($handle) use ($commandsToKeep): void { yield $this->reopenContentStreamWithoutConstraintChecks( $workspace->currentContentStreamId ); - throw WorkspaceRebaseFailed::duringDiscard($commandSimulator->getConflictingEvents()); + match ($workspace->status) { + // If the workspace is up-to-date it must be a problem regarding that the order of events cannot be changed + WorkspaceStatus::UP_TO_DATE => + throw PartialWorkspaceRebaseFailed::duringPartialDiscard($commandSimulator->getConflictingEvents()), + // If the workspace is outdated we cannot know for sure but suspect that the conflict arose due to changes in the base workspace. + WorkspaceStatus::OUTDATED => + throw WorkspaceRebaseFailed::duringDiscard($commandSimulator->getConflictingEvents()) + }; } yield from $this->forkNewContentStreamAndApplyEvents( @@ -671,12 +684,11 @@ private function handleDiscardWorkspace( return; } - $workspaceContentStreamVersion = $this->requireOpenContentStreamAndVersion($workspace, $commandHandlingDependencies); + $this->requireContentStreamToNotBeClosed($workspace->currentContentStreamId, $commandHandlingDependencies); $baseWorkspaceContentStreamVersion = $this->requireOpenContentStreamAndVersion($baseWorkspace, $commandHandlingDependencies); yield from $this->discardWorkspace( $workspace, - $workspaceContentStreamVersion, $baseWorkspace, $baseWorkspaceContentStreamVersion, $command->newContentStreamId @@ -688,7 +700,6 @@ private function handleDiscardWorkspace( */ private function discardWorkspace( Workspace $workspace, - Version $workspaceContentStreamVersion, Workspace $baseWorkspace, Version $baseWorkspaceContentStreamVersion, ContentStreamId $newContentStream diff --git a/Classes/Feature/WorkspaceRebase/Exception/PartialWorkspaceRebaseFailed.php b/Classes/Feature/WorkspaceRebase/Exception/PartialWorkspaceRebaseFailed.php new file mode 100644 index 0000000..c16946b --- /dev/null +++ b/Classes/Feature/WorkspaceRebase/Exception/PartialWorkspaceRebaseFailed.php @@ -0,0 +1,74 @@ +first()?->getException() + ); + } + + public static function duringPartialDiscard(ConflictingEvents $conflictingEvents): self + { + return new self( + $conflictingEvents, + sprintf('Discard failed, events cannot be reordered as filtered: %s', self::renderMessage($conflictingEvents)), + 1729974982, + $conflictingEvents->first()?->getException() + ); + } + + private static function renderMessage(ConflictingEvents $conflictingEvents): string + { + $firstConflict = $conflictingEvents->first(); + return sprintf('"%s" and %d further ordering conflicts', $firstConflict?->getException()->getMessage(), count($conflictingEvents) - 1); + } +} diff --git a/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php b/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php index 499ea7a..45849b8 100644 --- a/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php +++ b/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php @@ -19,7 +19,7 @@ /** * @api this exception contains information about what exactly went wrong during rebase */ -final class WorkspaceRebaseFailed extends \Exception +final class WorkspaceRebaseFailed extends \RuntimeException { private function __construct( public readonly ConflictingEvents $conflictingEvents,