Skip to content

Commit 9645c40

Browse files
authored
Add workspaces:publish command (#6432)
1 parent 15262b7 commit 9645c40

File tree

4 files changed

+166
-1
lines changed

4 files changed

+166
-1
lines changed

.docker/zz-php.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ variables_order = GPCS
33
error_reporting = E_ALL & ~E_DEPRECATED
44
date.timezone = "UTC"
55
sendmail_path = "true"
6-
memory_limit = 512M
6+
memory_limit = 1024M
77

88
[xdebug]
99
xdebug.mode = off

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ sut/modules/contrib
2727
# Test fixtures
2828
sut/drush/sites/synctest.site.yml
2929
/tests/.phpunit.result.cache
30+
31+
# Code tools
32+
.claude
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace Drush\Commands\core;
4+
5+
use Drupal\Core\Entity\EntityTypeManagerInterface;
6+
use Drupal\workspaces\WorkspaceOperationFactory;
7+
use Drush\Attributes as CLI;
8+
use Drush\Commands\AutowireTrait;
9+
use Drush\Style\DrushStyle;
10+
use Psr\Container\ContainerInterface;
11+
use Symfony\Component\Console\Attribute\AsCommand;
12+
use Symfony\Component\Console\Command\Command;
13+
use Symfony\Component\Console\Input\InputArgument;
14+
use Symfony\Component\Console\Input\InputInterface;
15+
use Symfony\Component\Console\Output\OutputInterface;
16+
17+
#[AsCommand(
18+
name: self::NAME,
19+
description: 'Publish a workspace.'
20+
)]
21+
#[CLI\ValidateModulesEnabled(modules: ['workspaces'])]
22+
final class WorkspacesCommand extends Command
23+
{
24+
use AutowireTrait;
25+
26+
const NAME = 'workspaces:publish';
27+
28+
protected ?WorkspaceOperationFactory $workspacesOperationFactory = null;
29+
30+
/**
31+
* Constructs a WorkspacesCommands object.
32+
*/
33+
public function __construct(
34+
private readonly EntityTypeManagerInterface $entityTypeManager,
35+
protected readonly ContainerInterface $container,
36+
) {
37+
parent::__construct();
38+
39+
if ($container->has('workspaces.operation_factory')) {
40+
$this->workspacesOperationFactory = $container->get('workspaces.operation_factory');
41+
}
42+
}
43+
44+
protected function configure()
45+
{
46+
$this
47+
->addArgument('id', InputArgument::REQUIRED, 'The workspace to publish.')
48+
->addUsage('workspaces:publish stage');
49+
}
50+
51+
52+
protected function execute(InputInterface $input, OutputInterface $output): int
53+
{
54+
$io = new DrushStyle($input, $output);
55+
$id = $input->getArgument('id');
56+
/** @var \Drupal\workspaces\Entity\Workspace $workspace */
57+
$workspace = $this->entityTypeManager->getStorage('workspace')->load($id);
58+
if (!$workspace) {
59+
throw new \Exception(dt('Workspace @id not found.', ['@id' => $id]));
60+
}
61+
62+
$workspace_publisher = $this->workspacesOperationFactory->getPublisher($workspace);
63+
64+
// Does this workspace have any content to publish?
65+
$diff = $workspace_publisher->getDifferringRevisionIdsOnSource();
66+
if (empty($diff)) {
67+
$io->success(sprintf('There are no changes that can be published from %s to %s', $workspace->label(), $workspace_publisher->getTargetLabel()));
68+
return self::SUCCESS;
69+
}
70+
71+
$workspace->publish();
72+
$io->success(sprintf('Workspace %s published.', $workspace->label()));
73+
return self::SUCCESS;
74+
}
75+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Unish;
6+
7+
use Drupal\node\Entity\Node;
8+
use Drupal\workspaces\WorkspaceManagerInterface;
9+
use Drush\Commands\core\WorkspacesCommand;
10+
use Drush\Commands\pm\PmInstallCommand;
11+
12+
/**
13+
* Tests Workspaces commands
14+
*
15+
* @group commands
16+
*/
17+
class WorkspacesTest extends UnishIntegrationTestCase
18+
{
19+
private WorkspaceManagerInterface $workspaceManager;
20+
21+
protected function setUp(): void
22+
{
23+
parent::setUp();
24+
$this->drush(PmInstallCommand::NAME, ['workspaces', 'node']);
25+
$this->workspaceManager = \Drupal::service('workspaces.manager');
26+
27+
// Create article content type if it doesn't exist
28+
$node_types = \Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple();
29+
if (!isset($node_types['article'])) {
30+
$article_type = \Drupal\node\Entity\NodeType::create([
31+
'type' => 'article',
32+
'name' => 'Article',
33+
]);
34+
$article_type->save();
35+
}
36+
37+
// Create a test workspace if it doesn't exist
38+
$workspace_storage = \Drupal::entityTypeManager()->getStorage('workspace');
39+
$existing_workspace = $workspace_storage->load('stage');
40+
if (!$existing_workspace) {
41+
$workspace = \Drupal\workspaces\Entity\Workspace::create([
42+
'id' => 'stage',
43+
'label' => 'Stage',
44+
]);
45+
$workspace->save();
46+
}
47+
48+
// Set the stage workspace as active and create content in it
49+
$stage_workspace = $workspace_storage->load('stage');
50+
$this->workspaceManager->setActiveWorkspace($stage_workspace);
51+
52+
// Create a sample node in the workspace context
53+
$node = Node::create([
54+
'type' => 'article',
55+
'title' => 'Test Node in Workspace',
56+
'body' => 'This is a test node created in the stage workspace.',
57+
'status' => 1,
58+
]);
59+
$node->save();
60+
}
61+
62+
public function testWorkspaces(): void
63+
{
64+
// Test that workspace has content to publish
65+
$workspace_id = 'stage';
66+
67+
// Publish the workspace
68+
$this->drush(WorkspacesCommand::NAME, [$workspace_id]);
69+
$this->assertStringContainsString('Workspace Stage published', $this->getErrorOutput());
70+
71+
// Verify no more changes exist after publishing
72+
$this->drush(WorkspacesCommand::NAME, [$workspace_id]);
73+
$this->assertStringContainsString('There are no changes that can be published', $this->getErrorOutput());
74+
}
75+
76+
/**
77+
* {@inheritdoc}
78+
*/
79+
protected function tearDown(): void
80+
{
81+
// Cleanup the test workspace (this should also handle content deletion)
82+
$this->drush('entity:delete', ['workspace', 'stage'], ['yes' => true]);
83+
$this->drush('entity:delete', ['node'], ['yes' => true, 'bundle' => 'article']);
84+
$this->drush('pm:uninstall', ['workspaces', 'node'], ['yes' => true]);
85+
parent::tearDown();
86+
}
87+
}

0 commit comments

Comments
 (0)