Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Highlevel Workspace API #4943

Merged
merged 38 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d5147c2
Implement workspace publisher to be used, e.g. by the Neos UI
Mar 14, 2024
e1cf530
Merge branch '9.0' into publishingBonanza
Mar 14, 2024
2a3d0f0
Merge remote-tracking branch 'upstream/9.0' into publishingBonanza
grebaldi Mar 17, 2024
eb72082
BUGFIX: Remove workspaceName from NodeIdToPublishOrDiscard invokation…
grebaldi Mar 18, 2024
01d483b
BUGFIX: Retrieve projection state ´ChangeFinder` rather than `ChangeP…
grebaldi Mar 18, 2024
b2944d1
TASK: Adjust use statements for `ContentRepositoryId` in WorkspacePub…
grebaldi Mar 18, 2024
6d956e5
TASK: Consider removal attachment point when checking if a change is …
grebaldi Mar 18, 2024
1ed41e2
Merge branch '9.0' into publishingBonanza
Mar 19, 2024
85867c8
Pacify linter
Mar 19, 2024
ea47c0d
TASK: Make WorkspacePublisher final
grebaldi Mar 20, 2024
a3ae813
TASK: Use NodeTypeNameFactory for special node type names in Workspac…
grebaldi Mar 20, 2024
91fbb50
Clarify command and command method names
Mar 20, 2024
2a86e89
Clarify command and command method names
Mar 20, 2024
01160c8
Merge branch 'publishingBonanza' of github.com:neos/neos-development-…
Mar 20, 2024
78a04ec
Reorder command constructors
Mar 20, 2024
ff331a6
Introduce constraint checks
Mar 20, 2024
53a02f2
Add missing return type
Mar 20, 2024
eb30da9
Add deprecation comment
Mar 21, 2024
8ad2aa9
Merge branch '9.0' into publishingBonanza
Mar 28, 2024
952a611
Refactor WorkspacePublisher to Workspace and move command DTOs to Neo…
Mar 28, 2024
48f7910
un-singleton workspace
Mar 28, 2024
81d5418
Absorb further functionality into workspace model
Mar 29, 2024
a087307
BUGFIX: Use `$workspace->name->value` in all console outputs of Works…
grebaldi Mar 29, 2024
6819d81
Merge branch '9.0' into publishingBonanza
Apr 1, 2024
ee1570e
Introduce publishing and discarding result models
Apr 1, 2024
e41a649
adjust workspace factory name
Apr 2, 2024
9f2ffad
Adjust to forgiving node type manager
Apr 2, 2024
99d5fc8
Expose rebase error handling strategy in workspace
Apr 3, 2024
2264001
TASK: Mark internal/experimental methods in new Neos `Workspace`
mhsdesign Apr 3, 2024
2464cfe
TASK: Document mutation behaviour of `Workspace`
mhsdesign Apr 3, 2024
f67bd96
TASK: Turn Neos' Workspace model into singleton for consistent behavior
mhsdesign Apr 3, 2024
bcd2147
TASK: Expose `ContentRepositoryId` in Neos' Workspace
mhsdesign Apr 3, 2024
0752506
Merge pull request #4974 from mhsdesign/task/publishingBonanza-review
nezaniel Apr 4, 2024
613b259
restore promoted workspace name and deprecation list
Apr 4, 2024
9c01966
TASK: Rename `WorkspaceFactory` to `WorkspaceProvider`
mhsdesign Apr 4, 2024
e35f59f
TASK: Rename to `retrieveForWorkspaceName`
mhsdesign Apr 4, 2024
763f74c
Merge branch '9.0' into publishingBonanza
Apr 5, 2024
cbb8b54
Adjust workspace provider methods
Apr 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 34 additions & 35 deletions Neos.Neos/Classes/Command/WorkspaceCommandController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\BaseWorkspaceDoesNotExist;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists;
use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\DeleteWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Command\RebaseWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Dto\RebaseErrorHandlingStrategy;
use Neos\ContentRepository\Core\Projection\Workspace\Workspace;
use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceStatus;
Expand All @@ -39,6 +36,7 @@
use Neos\Flow\Cli\Exception\StopCommandException;
use Neos\Flow\Persistence\PersistenceManagerInterface;
use Neos\Neos\Domain\Service\UserService;
use Neos\Neos\Domain\Workspace\WorkspaceProvider;
use Neos\Neos\PendingChangesProjection\ChangeFinder;

/**
Expand All @@ -56,6 +54,9 @@ class WorkspaceCommandController extends CommandController
#[Flow\Inject]
protected ContentRepositoryRegistry $contentRepositoryRegistry;

#[Flow\Inject]
protected WorkspaceProvider $workspaceProvider;

/**
* Publish changes of a workspace
*
Expand All @@ -66,16 +67,16 @@ class WorkspaceCommandController extends CommandController
*/
public function publishCommand(string $workspace, string $contentRepositoryIdentifier = 'default'): void
{
$contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier);
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);

$contentRepository->handle(PublishWorkspace::create(
WorkspaceName::fromString($workspace),
))->block();
// @todo: bypass access control
$workspace = $this->workspaceProvider->provideForWorkspaceName(
ContentRepositoryId::fromString($contentRepositoryIdentifier),
WorkspaceName::fromString($workspace)
);
$workspace->publishAllChanges();

$this->outputLine(
'Published all nodes in workspace %s to its base workspace',
[$workspace]
[$workspace->name->value]
);
}

Expand All @@ -90,20 +91,19 @@ public function publishCommand(string $workspace, string $contentRepositoryIdent
*/
public function discardCommand(string $workspace, string $contentRepositoryIdentifier = 'default'): void
{
$contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier);
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
// @todo: bypass access control
$workspace = $this->workspaceProvider->provideForWorkspaceName(
ContentRepositoryId::fromString($contentRepositoryIdentifier),
WorkspaceName::fromString($workspace)
);

try {
$contentRepository->handle(
DiscardWorkspace::create(
WorkspaceName::fromString($workspace),
)
)->block();
$workspace->discardAllChanges();
} catch (WorkspaceDoesNotExist $exception) {
$this->outputLine('Workspace "%s" does not exist', [$workspace]);
$this->outputLine('Workspace "%s" does not exist', [$workspace->name->value]);
$this->quit(1);
}
$this->outputLine('Discarded all nodes in workspace %s', [$workspace]);
$this->outputLine('Discarded all nodes in workspace %s', [$workspace->name->value]);
}

/**
Expand All @@ -118,29 +118,25 @@ public function discardCommand(string $workspace, string $contentRepositoryIdent
*/
public function rebaseCommand(string $workspace, string $contentRepositoryIdentifier = 'default', bool $force = false): void
{
$contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier);
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
// @todo: bypass access control
$workspace = $this->workspaceProvider->provideForWorkspaceName(
ContentRepositoryId::fromString($contentRepositoryIdentifier),
WorkspaceName::fromString($workspace)
);

try {
$rebaseCommand = RebaseWorkspace::create(
WorkspaceName::fromString($workspace),
);
if ($force) {
$rebaseCommand = $rebaseCommand->withErrorHandlingStrategy(RebaseErrorHandlingStrategy::STRATEGY_FORCE);
}
$contentRepository->handle($rebaseCommand)->block();
$workspace->rebase($force ? RebaseErrorHandlingStrategy::STRATEGY_FORCE : RebaseErrorHandlingStrategy::STRATEGY_FAIL);
} catch (WorkspaceDoesNotExist $exception) {
$this->outputLine('Workspace "%s" does not exist', [$workspace]);
$this->outputLine('Workspace "%s" does not exist', [$workspace->name->value]);
$this->quit(1);
}

$workspaceObject = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::fromString($workspace));
if ($workspaceObject && $workspaceObject->status === WorkspaceStatus::OUTDATED_CONFLICT) {
if ($workspace->getCurrentStatus() === WorkspaceStatus::OUTDATED_CONFLICT) {
$this->outputLine('Rebasing of workspace %s is not possible due to conflicts. You can try the --force option.', [$workspace]);
$this->quit(1);
}

$this->outputLine('Rebased workspace %s', [$workspace]);
$this->outputLine('Rebased workspace %s', [$workspace->name->value]);
}

/**
Expand Down Expand Up @@ -303,9 +299,12 @@ public function deleteCommand(string $workspace, bool $force = false, string $co
);
$this->quit(5);
}
$contentRepository->handle(
DiscardWorkspace::create($workspaceName)
)->block();
// @todo bypass access control?
$workspace = $this->workspaceProvider->provideForWorkspaceName(
$contentRepositoryId,
$workspaceName
);
$workspace->discardAllChanges();
}

$contentRepository->handle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,14 @@
namespace Neos\Neos\Controller\Module\Management;

use Doctrine\DBAL\DBALException;
use JsonException;
use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists;
use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\ChangeWorkspaceOwner;
use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\DeleteWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\RenameWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardIndividualNodesFromWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishIndividualNodesFromWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdsToPublishOrDiscard;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter;
Expand Down Expand Up @@ -62,6 +59,9 @@
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\Domain\Service\UserService;
use Neos\Neos\Domain\Service\WorkspaceNameBuilder;
use Neos\Neos\Domain\Workspace\DiscardAllChanges;
use Neos\Neos\Domain\Workspace\PublishAllChanges;
use Neos\Neos\Domain\Workspace\WorkspaceProvider;
use Neos\Neos\FrontendRouting\NodeAddress;
use Neos\Neos\FrontendRouting\NodeAddressFactory;
use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult;
Expand Down Expand Up @@ -96,6 +96,9 @@ class WorkspacesController extends AbstractModuleController
#[Flow\Inject]
protected PackageManager $packageManager;

#[Flow\Inject]
protected WorkspaceProvider $workspaceProvider;

/**
* Display a list of unpublished content
*
Expand Down Expand Up @@ -648,20 +651,23 @@ public function publishWorkspaceAction(WorkspaceName $workspace): void
{
$contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())
->contentRepositoryId;
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
$contentRepository->handle(
PublishWorkspace::create(
$workspace
)
)->block();
$workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspace);
/** @var Workspace $workspace Otherwise the command handler would have thrown an exception */
/** @todo send from UI */
$command = new PublishAllChanges(
$contentRepositoryId,
$workspace
);

$workspace = $this->workspaceProvider->provideForWorkspaceName(
$command->contentRepositoryId,
$command->workspaceName
);
$workspace->publishAllChanges();
/** @var WorkspaceName $baseWorkspaceName Otherwise the command handler would have thrown an exception */
$baseWorkspaceName = $workspace->baseWorkspaceName;
$baseWorkspaceName = $workspace->getCurrentBaseWorkspaceName();
$this->addFlashMessage($this->translator->translateById(
'workspaces.allChangesInWorkspaceHaveBeenPublished',
[
htmlspecialchars($workspace->workspaceName->value),
htmlspecialchars($workspace->name->value),
htmlspecialchars($baseWorkspaceName->value)
],
null,
Expand All @@ -681,16 +687,20 @@ public function discardWorkspaceAction(WorkspaceName $workspace): void
{
$contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())
->contentRepositoryId;
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
$contentRepository->handle(
DiscardWorkspace::create(
$workspace,
)
)->block();
/** @todo send from UI */
$command = new DiscardAllChanges(
$contentRepositoryId,
$workspace
);
$workspace = $this->workspaceProvider->provideForWorkspaceName(
$command->contentRepositoryId,
$command->workspaceName
);
$workspace->discardAllChanges();

$this->addFlashMessage($this->translator->translateById(
'workspaces.allChangesInWorkspaceHaveBeenDiscarded',
[htmlspecialchars($workspace->value)],
[htmlspecialchars($workspace->name->value)],
null,
null,
'Modules',
Expand All @@ -703,7 +713,7 @@ public function discardWorkspaceAction(WorkspaceName $workspace): void
* Computes the number of added, changed and removed nodes for the given workspace
*
* @return array<string,int>
* @throws JsonException
* @throws \JsonException
*/
protected function computeChangesCount(Workspace $selectedWorkspace, ContentRepository $contentRepository): array
{
Expand All @@ -729,7 +739,7 @@ protected function computeChangesCount(Workspace $selectedWorkspace, ContentRepo
/**
* Builds an array of changes for sites in the given workspace
* @return array<string,mixed>
* @throws JsonException
* @throws \JsonException
*/
protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepository $contentRepository): array
{
Expand Down
45 changes: 45 additions & 0 deletions Neos.Neos/Classes/Domain/Workspace/DiscardAllChanges.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

declare(strict_types=1);

namespace Neos\Neos\Domain\Workspace;

use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Annotations as Flow;

/**
* The command DTO to communicate discarding of all changes recorded in a given workspace
*
* @internal for communication within Neos only
*/
#[Flow\Proxy(false)]
final readonly class DiscardAllChanges
{
public function __construct(
public ContentRepositoryId $contentRepositoryId,
public WorkspaceName $workspaceName,
) {
}

/**
* @param array<string,string> $values
*/
public static function fromArray(array $values): self
{
return new self(
ContentRepositoryId::fromString($values['contentRepositoryId']),
WorkspaceName::fromString($values['workspaceName']),
);
}
}
31 changes: 31 additions & 0 deletions Neos.Neos/Classes/Domain/Workspace/DiscardingResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

declare(strict_types=1);

namespace Neos\Neos\Domain\Workspace;

use Neos\Flow\Annotations as Flow;

/**
* The discarding result DTO
*
* @internal for communication within Neos only
*/
#[Flow\Proxy(false)]
final readonly class DiscardingResult
{
public function __construct(
public int $numberOfDiscardedChanges,
) {
}
}
45 changes: 45 additions & 0 deletions Neos.Neos/Classes/Domain/Workspace/PublishAllChanges.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

declare(strict_types=1);

namespace Neos\Neos\Domain\Workspace;

use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Annotations as Flow;

/**
* The command DTO to communicate publication of all changes recorded in a given workspace
*
* @internal for communication within Neos only
*/
#[Flow\Proxy(false)]
final readonly class PublishAllChanges
{
public function __construct(
public ContentRepositoryId $contentRepositoryId,
public WorkspaceName $workspaceName,
) {
}

/**
* @param array<string,string> $values
*/
public static function fromArray(array $values): self
{
return new self(
ContentRepositoryId::fromString($values['contentRepositoryId']),
WorkspaceName::fromString($values['workspaceName']),
);
}
}
Loading
Loading