Skip to content

Commit 2f59cc8

Browse files
committed
fix: abort command when active team conflicts with project team
1 parent 1a942d1 commit 2f59cc8

File tree

5 files changed

+417
-0
lines changed

5 files changed

+417
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli\EventListener;
15+
16+
use Illuminate\Support\Arr;
17+
use Symfony\Component\Console\Command\Command;
18+
use Symfony\Component\Console\ConsoleEvents;
19+
use Symfony\Component\Console\Event\ConsoleCommandEvent;
20+
use Symfony\Component\Console\Exception\RuntimeException;
21+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
22+
use Ymir\Cli\ApiClient;
23+
use Ymir\Cli\CliConfiguration;
24+
use Ymir\Cli\Command\LoginCommand;
25+
use Ymir\Cli\Command\Project\InitializeProjectCommand;
26+
use Ymir\Cli\Command\Team;
27+
use Ymir\Cli\Project\Configuration\ProjectConfiguration;
28+
29+
class ProjectTeamGuardSubscriber implements EventSubscriberInterface
30+
{
31+
/**
32+
* Commands that exempted from the guard check.
33+
*/
34+
private const IGNORED_COMMANDS = [
35+
'help',
36+
'list',
37+
LoginCommand::NAME,
38+
InitializeProjectCommand::NAME,
39+
Team\CurrentTeamCommand::NAME,
40+
Team\ListTeamsCommand::NAME,
41+
Team\SelectTeamCommand::NAME,
42+
];
43+
44+
/**
45+
* The API client that interacts with the Ymir API.
46+
*
47+
* @var ApiClient
48+
*/
49+
private $apiClient;
50+
51+
/**
52+
* The global Ymir CLI configuration.
53+
*
54+
* @var CliConfiguration
55+
*/
56+
private $cliConfiguration;
57+
58+
/**
59+
* The Ymir project configuration.
60+
*
61+
* @var ProjectConfiguration
62+
*/
63+
private $projectConfiguration;
64+
65+
/**
66+
* Constructor.
67+
*/
68+
public function __construct(ApiClient $apiClient, CliConfiguration $cliConfiguration, ProjectConfiguration $projectConfiguration)
69+
{
70+
$this->apiClient = $apiClient;
71+
$this->cliConfiguration = $cliConfiguration;
72+
$this->projectConfiguration = $projectConfiguration;
73+
}
74+
75+
/**
76+
* {@inheritdoc}
77+
*/
78+
public static function getSubscribedEvents()
79+
{
80+
return [
81+
ConsoleEvents::COMMAND => 'onConsoleCommand',
82+
];
83+
}
84+
85+
/**
86+
* Checks that the current team matches the project team if in a project directory.
87+
*/
88+
public function onConsoleCommand(ConsoleCommandEvent $event)
89+
{
90+
if (!$this->projectConfiguration->exists() || !$event->getCommand() instanceof Command || in_array($event->getCommand()->getName(), self::IGNORED_COMMANDS)) {
91+
return;
92+
}
93+
94+
$activeTeamId = $this->cliConfiguration->getActiveTeamId();
95+
$projectTeam = Arr::get($this->apiClient->getProject($this->projectConfiguration->getProjectId()), 'provider.team');
96+
97+
if (empty($projectTeam['id']) || $activeTeamId === $projectTeam['id']) {
98+
return;
99+
}
100+
101+
$activeTeam = $this->apiClient->getTeam($activeTeamId);
102+
103+
throw new RuntimeException(sprintf('Your active team "%s" does not match the project\'s team "%s". Use the "%s %d" command to switch to the project\'s team.', $activeTeam['name'], $projectTeam['name'], Team\SelectTeamCommand::NAME, $projectTeam['id']));
104+
}
105+
}

tests/Mock/CommandMockTrait.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli\Tests\Mock;
15+
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
use Symfony\Component\Console\Command\Command;
18+
19+
trait CommandMockTrait
20+
{
21+
/**
22+
* Get a mock of a Command object.
23+
*/
24+
private function getCommandMock(): MockObject
25+
{
26+
return $this->getMockBuilder(Command::class)
27+
->disableOriginalConstructor()
28+
->getMock();
29+
}
30+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli\Tests\Mock;
15+
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
19+
trait InputInterfaceMockTrait
20+
{
21+
/**
22+
* Get a mock of a InputInterface object.
23+
*/
24+
private function getInputInterfaceMock(): MockObject
25+
{
26+
return $this->getMockBuilder(InputInterface::class)
27+
->getMock();
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli\Tests\Mock;
15+
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
19+
trait OutputInterfaceMockTrait
20+
{
21+
/**
22+
* Get a mock of a OutputInterface object.
23+
*/
24+
private function getOutputInterfaceMock(): MockObject
25+
{
26+
return $this->getMockBuilder(OutputInterface::class)
27+
->getMock();
28+
}
29+
}

0 commit comments

Comments
 (0)