Skip to content

Commit 320f7f5

Browse files
committed
Add a basic implementation for a list features command
The command will find and list all of the features that have been added to rollout.
1 parent 51d6e9f commit 320f7f5

File tree

8 files changed

+329
-1
lines changed

8 files changed

+329
-1
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"require": {
1414
"php": ">=7.0",
1515
"illuminate/cache": "^5.3|^5.4",
16+
"illuminate/console": "^5.3|^5.4",
1617
"illuminate/support": "^5.3|^5.4",
1718
"opensoft/rollout": "^2.2"
1819
},

src/Console/ListFeatures.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace Jaspaul\LaravelRollout\Console;
4+
5+
use Opensoft\Rollout\Rollout;
6+
use Illuminate\Console\Command;
7+
use Jaspaul\LaravelRollout\FeaturePresenter;
8+
9+
class ListFeatures extends Command
10+
{
11+
/**
12+
* The name and signature of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $signature = 'rollout:list-features';
17+
18+
/**
19+
* The console command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Returns a list of all the features that have been created.';
24+
25+
/**
26+
* The rollout service.
27+
*
28+
* @var \Opensoft\Rollout\Rollout
29+
*/
30+
protected $rollout;
31+
32+
/**
33+
* Initialize our list features command with an instance of the rollout service.
34+
*
35+
* @param \Opensoft\Rollout\Rollout $rollout
36+
* The rollout service.
37+
*/
38+
public function __construct(Rollout $rollout)
39+
{
40+
$this->rollout = $rollout;
41+
}
42+
43+
/**
44+
* Returns the feature rows.
45+
*
46+
* @return array
47+
* A list of features.
48+
*/
49+
public function getRows() : array
50+
{
51+
$rows = [];
52+
53+
$features = $this->rollout->features();
54+
55+
foreach ($features as $name)
56+
{
57+
$feature = new FeaturePresenter($this->rollout->get($name));
58+
59+
$rows[] = [
60+
'name' => $feature->getName(),
61+
'status' => $feature->getDisplayStatus()
62+
];
63+
}
64+
65+
return $rows;
66+
}
67+
68+
/**
69+
* Outputs a table containing the features configured in rollout.
70+
*
71+
* @return void
72+
*/
73+
public function handle()
74+
{
75+
$headers = ['name', 'status'];
76+
$rows = $this->getRows();
77+
78+
$this->table($headers, $rows);
79+
}
80+
}

src/FeaturePresenter.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace Jaspaul\LaravelRollout;
4+
5+
use Opensoft\Rollout\Feature;
6+
7+
class FeaturePresenter
8+
{
9+
/**
10+
* A list of available status messages.
11+
*
12+
* @var array
13+
*/
14+
public static $statuses = [
15+
'all' => 'Active for everyone.',
16+
'request_param' => 'Active with a request parameter.',
17+
'percentage' => 'Active via percentage rollout.',
18+
'whitelist' => 'Active via group or user whitelist.',
19+
'disabled' => 'Deactivated globally.'
20+
];
21+
22+
/**
23+
* The feature we're presenting.
24+
*
25+
* @var \Opensoft\Rollout\Feature
26+
*/
27+
protected $feature;
28+
29+
/**
30+
* Sets up our local feature.
31+
*
32+
* @param \Opensoft\Rollout\Feature $feature
33+
* The feature to present.
34+
*/
35+
public function __construct(Feature $feature)
36+
{
37+
$this->feature = $feature;
38+
}
39+
40+
/**
41+
* Returns the name to render for the feature.
42+
*
43+
* @return string
44+
* The name of the feature.
45+
*/
46+
public function getName() : string
47+
{
48+
return $this->feature->getName();
49+
}
50+
51+
/**
52+
* Returns a human readable status for the feature.
53+
*
54+
* @return string
55+
* The status of the feature.
56+
*/
57+
public function getDisplayStatus() : string
58+
{
59+
if ($this->feature->getPercentage() === 100) {
60+
return self::$statuses['all'];
61+
}
62+
63+
if ($this->feature->getRequestParam()) {
64+
return self::$statuses['request_param'];
65+
}
66+
67+
if ($this->feature->getPercentage() > 0) {
68+
return self::$statuses['percentage'];
69+
}
70+
71+
if (count($this->feature->getGroups()) > 0 || count($this->feature->getUsers()) > 0) {
72+
return self::$statuses['whitelist'];
73+
}
74+
75+
return self::$statuses['disabled'];
76+
}
77+
}

src/ServiceProvider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Opensoft\Rollout\Rollout;
66
use Jaspaul\LaravelRollout\Drivers\Cache;
7+
use Jaspaul\LaravelRollout\Console\ListFeatures;
78
use Illuminate\Support\ServiceProvider as IlluminateServiceProvider;
89

910
class ServiceProvider extends IlluminateServiceProvider
@@ -18,5 +19,7 @@ public function boot()
1819
$this->app->singleton(Rollout::class, function ($app) {
1920
return new Rollout(new Cache($app->make('cache.store')));
2021
});
22+
23+
$this->commands([ListFeatures::class]);
2124
}
2225
}

tests/Console/ListFeaturesTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Tests\Drivers;
4+
5+
use Tests\TestCase;
6+
use Opensoft\Rollout\Rollout;
7+
use Illuminate\Cache\ArrayStore;
8+
use Illuminate\Cache\Repository;
9+
use Jaspaul\LaravelRollout\Drivers\Cache;
10+
use Jaspaul\LaravelRollout\Console\ListFeatures;
11+
12+
class ListFeaturesTest extends TestCase
13+
{
14+
private $command;
15+
private $rollout;
16+
17+
/**
18+
* @before
19+
*/
20+
function setup_command()
21+
{
22+
$this->rollout = new Rollout(new Cache(new Repository(new ArrayStore())));
23+
$this->command = new ListFeatures($this->rollout);
24+
}
25+
26+
/**
27+
* @test
28+
*/
29+
function get_rows_returns_an_empty_set_when_no_features_exist()
30+
{
31+
$result = $this->command->getRows();
32+
$this->assertEmpty($result);
33+
}
34+
35+
/**
36+
* @test
37+
*/
38+
function get_rows_returns_the_features_that_were_set()
39+
{
40+
$this->rollout->get('test');
41+
42+
$result = $this->command->getRows();
43+
44+
$this->assertEquals(1, count($result));
45+
$this->assertEquals(
46+
[['name' => 'test', 'status' => 'Deactivated globally.']], $result
47+
);
48+
}
49+
}

tests/Drivers/CacheTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Tests;
3+
namespace Tests\Drivers;
44

55
use Mockery;
66
use Tests\TestCase;

tests/FeaturePresenterTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
namespace Tests;
4+
5+
use Opensoft\Rollout\Feature;
6+
use Jaspaul\LaravelRollout\FeaturePresenter;
7+
8+
class FeaturePresenterTest extends TestCase
9+
{
10+
/**
11+
* @test
12+
*/
13+
function get_name_returns_the_name_of_the_feature()
14+
{
15+
$feature = new Feature('name');
16+
$presenter = new FeaturePresenter($feature);
17+
18+
$this->assertEquals('name', $presenter->getName());
19+
}
20+
21+
/**
22+
* @test
23+
*/
24+
function get_display_status_returns_the_all_message_if_the_feature_is_100_percent_enabled()
25+
{
26+
$feature = new Feature('name');
27+
$feature->setPercentage(100);
28+
29+
$presenter = new FeaturePresenter($feature);
30+
31+
$this->assertEquals(FeaturePresenter::$statuses['all'], $presenter->getDisplayStatus());
32+
}
33+
34+
/**
35+
* @test
36+
*/
37+
function get_display_status_returns_the_request_parameter_message_if_only_a_request_parameter_is_set()
38+
{
39+
$feature = new Feature('name');
40+
$feature->setRequestParam('derp');
41+
42+
$presenter = new FeaturePresenter($feature);
43+
44+
$this->assertEquals(FeaturePresenter::$statuses['request_param'], $presenter->getDisplayStatus());
45+
}
46+
47+
/**
48+
* @test
49+
*/
50+
function get_display_status_returns_the_percentage_message_if_it_is_enabled_for_more_than_0_but_less_than_100_percent_of_users()
51+
{
52+
$feature = new Feature('name');
53+
$feature->setPercentage(80);
54+
55+
$presenter = new FeaturePresenter($feature);
56+
57+
$this->assertEquals(FeaturePresenter::$statuses['percentage'], $presenter->getDisplayStatus());
58+
}
59+
60+
/**
61+
* @test
62+
*/
63+
function get_display_status_returns_the_whitelist_message_if_it_is_enabled_for_groups()
64+
{
65+
$feature = new Feature('name', '0||d');
66+
$presenter = new FeaturePresenter($feature);
67+
68+
$this->assertEquals(FeaturePresenter::$statuses['whitelist'], $presenter->getDisplayStatus());
69+
}
70+
71+
/**
72+
* @test
73+
*/
74+
function get_display_status_returns_the_whitelist_message_if_it_is_enabled_for_users()
75+
{
76+
$feature = new Feature('name', '0|a|');
77+
$presenter = new FeaturePresenter($feature);
78+
79+
$this->assertEquals(FeaturePresenter::$statuses['whitelist'], $presenter->getDisplayStatus());
80+
}
81+
82+
/**
83+
* @test
84+
*/
85+
function get_display_status_returns_the_whitelist_message_if_it_is_enabled_for_users_and_groups()
86+
{
87+
$feature = new Feature('name', '0|a|d');
88+
$presenter = new FeaturePresenter($feature);
89+
90+
$this->assertEquals(FeaturePresenter::$statuses['whitelist'], $presenter->getDisplayStatus());
91+
}
92+
}

tests/ServiceProviderTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Container\Container;
88
use Illuminate\Contracts\Cache\Repository;
99
use Jaspaul\LaravelRollout\ServiceProvider;
10+
use Jaspaul\LaravelRollout\Console\ListFeatures;
1011
use Illuminate\Support\ServiceProvider as IlluminateServiceProvider;
1112

1213
class ServiceProviderTest extends TestCase
@@ -46,4 +47,29 @@ function booting_registers_a_rollout_singleton_into_the_container()
4647
$result = $this->container->make(Rollout::class);
4748
$this->assertInstanceOf(Rollout::class, $result);
4849
}
50+
51+
/**
52+
* @test
53+
*/
54+
function booting_registers_our_commands()
55+
{
56+
$this->container->singleton('cache.store', function ($app) {
57+
return Mockery::mock(Repository::class);
58+
});
59+
60+
$serviceProvider = new TestServiceProvider($this->container);
61+
$serviceProvider->boot();
62+
63+
$this->assertEquals([ListFeatures::class], $serviceProvider->commands);
64+
}
65+
}
66+
67+
class TestServiceProvider extends ServiceProvider
68+
{
69+
public $commands;
70+
71+
public function commands($commands)
72+
{
73+
$this->commands = $commands;
74+
}
4975
}

0 commit comments

Comments
 (0)