From 0fa2c9b47746a3248ebdb4ac6d8a4e3a6304a78b Mon Sep 17 00:00:00 2001 From: James Brooks Date: Mon, 2 Jan 2017 18:35:03 +0000 Subject: [PATCH 1/4] Add cachet:install command --- app/Console/Commands/InstallCommand.php | 395 ++++++++++++++++++++++++ app/Console/Kernel.php | 2 + 2 files changed, 397 insertions(+) create mode 100644 app/Console/Commands/InstallCommand.php diff --git a/app/Console/Commands/InstallCommand.php b/app/Console/Commands/InstallCommand.php new file mode 100644 index 000000000000..870ae1dedde8 --- /dev/null +++ b/app/Console/Commands/InstallCommand.php @@ -0,0 +1,395 @@ + + */ +class InstallCommand extends Command +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'cachet:install'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Install Cachet'; + + /** + * The settings repository. + * + * @var \CachetHQ\Cache\Settings\Repository + */ + protected $settings; + + /** + * Create a new demo seeder command instance. + * + * @param \CachetHQ\Cache\Settings\Repository $settings + * + * @return void + */ + public function __construct(Repository $settings) + { + parent::__construct(); + + $this->settings = $settings; + } + + /** + * Execute the console command. + * + * @return void + */ + public function fire() + { + if (!$this->confirm('Do you want to install Cachet?')) { + $this->line('Installation aborted. Goodbye!'); + + return; + } + + $this->configureEnvironmentFile(); + $this->configureKey(); + $this->configureDatabase(); + $this->configureDrivers(); + $this->configureMail(); + $this->configureCachet(); + + $this->success('Cachet is installed ⚡'); + } + + /** + * Copy the environment file. + * + * @return void + */ + protected function configureEnvironmentFile() + { + $dir = app()->environmentPath(); + $file = app()->environmentFile(); + $path = "{$dir}/{$file}"; + + if (file_exists($path)) { + $this->line('Environment file already exists. Moving on.'); + + return; + } + + copy("$path.example", $path); + } + + /** + * Generate the app key. + * + * @return void + */ + protected function configureKey() + { + $this->call('key:generate'); + } + + /** + * Configure the database. + * + * @param array $default + * + * @return void + */ + protected function configureDatabase(array $default = []) + { + $config = array_merge([ + 'DB_DRIVER' => null, + 'DB_HOST' => null, + 'DB_DATABASE' => null, + 'DB_USERNAME' => null, + 'DB_PASSWORD' => null, + 'DB_PORT' => null, + 'DB_PREFIX' => null, + ], $default); + + $config['DB_DRIVER'] = $this->choice('Which database driver do you want to use?', [ + 'mysql' => 'MySQL', + 'postgresql' => 'PostgreSQL', + 'sqlite' => 'SQLite', + ], $config['DB_DRIVER']); + + if ($config['DB_DRIVER'] === 'sqlite') { + $config['DB_DATABASE'] = $this->ask('Please provide the full path to your SQLite file.', $config['DB_DATABASE']); + } else { + $config['DB_HOST'] = $this->ask("What is the host of your {$config['DB_DRIVER']} database?", $config['DB_HOST']); + + $config['DB_DATABASE'] = $this->ask('What is the name of the database that Cachet should use?', $config['DB_DATABASE']); + + $config['DB_USERNAME'] = $this->ask('What username should we connect with?', $config['DB_USERNAME']); + + $config['DB_PASSWORD'] = $this->secret('What password should we connect with?', $config['DB_PASSWORD']); + + if ($this->confirm('Is your database listening on a non-standard port number?')) { + $config['DB_PORT'] = $this->anticipate('What port number is your database using?', [3306, 5432], $config['DB_PORT']); + } + } + + if ($this->confirm('Do you want to use a prefix on the table names?')) { + $config['DB_PREFIX'] = $this->ask('Please enter the prefix now...', $config['DB_PREFIX']); + } + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + if (!$this->confirm('Are these settings correct?')) { + return $this->configureDatabase($config); + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure other drivers. + * + * @param array $default + * + * @return void + */ + protected function configureDrivers(array $default = []) + { + $config = array_merge([ + 'CACHE_DRIVER' => null, + 'SESSION_DRIVER' => null, + 'QUEUE_DRIVER' => null, + ], $default); + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + $config['CACHE_DRIVER'] = $this->choice('Which cache driver do you want to use?', [ + 'apc' => 'APC(u)', + 'array' => 'Array', + 'database' => 'Database', + 'file' => 'File', + 'memcached' => 'Memcached', + 'redis' => 'Redis', + ], $config['CACHE_DRIVER']); + + // We need to configure Redis. + if ($config['CACHE_DRIVER'] === 'redis') { + $this->configureRedis(); + } + + $config['SESSION_DRIVER'] = $this->choice('Which session driver do you want to use?', [ + 'apc' => 'APC(u)', + 'array' => 'Array', + 'database' => 'Database', + 'file' => 'File', + 'memcached' => 'Memcached', + 'redis' => 'Redis', + ], $config['SESSION_DRIVER']); + + // We need to configure Redis. + if ($config['SESSION_DRIVER'] === 'redis') { + $this->configureRedis(); + } + + $config['QUEUE_DRIVER'] = $this->choice('Which queue driver do you want to use?', [ + 'null' => 'None', + 'sync' => 'Synchronous', + 'database' => 'Database', + 'beanstalkd' => 'Beanstalk', + 'sqs' => 'Amazon SQS', + 'redis' => 'Redis', + ], $config['QUEUE_DRIVER']); + + // We need to configure Redis, but only if the cache driver wasn't redis. + if ($config['QUEUE_DRIVER'] === 'redis' && ($config['SESSION_DRIVER'] !== 'redis' || $config['CACHE_DRIVER'] !== 'redis')) { + $this->configureRedis(); + } + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + if (!$this->confirm('Are these settings correct?')) { + return $this->configureDrivers($config); + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure mail. + * + * @param array $config + * + * @return void + */ + protected function configureMail(array $config = []) + { + $config = array_merge([ + 'MAIL_DRIVER' => null, + 'MAIL_HOST' => null, + 'MAIL_PORT' => null, + 'MAIL_USERNAME' => null, + 'MAIL_PASSWORD' => null, + 'MAIL_ADDRESS' => null, + 'MAIL_NAME' => null, + 'MAIL_ENCRYPTION' => null, + ], $config); + + // Don't continue with these settings if we're not interested in notifications. + if (!$this->confirm('Do you want Cachet to send mail notifications?')) { + return; + } + + $config['MAIL_DRIVER'] = $this->choice('What driver do you want to use to send notifications?', [ + 'smtp' => 'SMTP', + 'mail' => 'Mail', + 'sendmail' => 'Sendmail', + 'mailgun' => 'Mailgun', + 'mandrill' => 'Mandrill', + 'ses' => 'Amazon SES', + 'sparkpost' => 'SparkPost', + 'log' => 'Log (Testing)', + ]); + + if (!$config['MAIL_DRIVER'] === 'log') { + if ($config['MAIL_DRIVER'] === 'smtp') { + $config['MAIL_HOST'] = $this->ask('Please supply your mail server host'); + } + + $config['MAIL_ADDRESS'] = $this->ask('What email address should we send notifications from?'); + $config['MAIL_USERNAME'] = $this->ask('What username should we connect as?'); + $config['MAIL_PASSWORD'] = $this->secret('What password should we connect with?'); + } + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + if (!$this->confirm('Are these settings correct?')) { + return $this->configureMail($config); + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure Cachet. + * + * @return void + */ + protected function configureCachet() + { + if ($this->confirm('Do you wish to use Cachet Beacon?')) { + $config['CACHET_BEACON'] = 'true'; + } + + if ($this->confirm('Do you wish to use Emoji? This requires a GitHub oAuth Token!')) { + $config['GITHUB_TOKEN'] = $this->ask('Please enter your GitHub oAuth Token'); + $config['CACHET_EMOJI'] = 'true'; + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure the redis connection. + * + * @return void + */ + protected function configureRedis() + { + $config = [ + 'REDIS_HOST' => null, + 'REDIS_DATABASE' => null, + 'REDIS_PORT' => null, + ]; + + $config['REDIS_HOST'] = $this->ask('What is the host of your redis server?'); + $config['REDIS_DATABASE'] = $this->ask('What is the name of the database that Cachet should use?'); + $config['REDIS_PORT'] = $this->ask('What port should Cachet use?', 6379); + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Format the configs into a pretty table that we can easily read. + * + * @param array $config + * + * @return void + */ + protected function formatConfigsTable(array $config) + { + $configRows = []; + + foreach ($config as $setting => $value) { + $configRows[] = compact('setting', 'value'); + } + + $this->table(['Setting', 'Value'], $configRows); + } + + /** + * Writes to the .env file with given parameters. + * + * @param string $key + * @param mixed $value + * + * @return void + */ + protected function writeEnv($key, $value) + { + $dir = app()->environmentPath(); + $file = app()->environmentFile(); + $path = "{$dir}/{$file}"; + + try { + (new Dotenv($dir, $file))->load(); + + $envKey = strtoupper($key); + $envValue = env($envKey) ?: 'null'; + + file_put_contents($path, str_replace( + "{$envKey}={$envValue}", + "{$envKey}={$value}", + file_get_contents($path) + )); + } catch (InvalidPathException $e) { + throw $e; + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 059aa0cc1c04..78bd5b441865 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -14,6 +14,7 @@ use CachetHQ\Cachet\Console\Commands\BeaconCommand; use CachetHQ\Cachet\Console\Commands\DemoMetricPointSeederCommand; use CachetHQ\Cachet\Console\Commands\DemoSeederCommand; +use CachetHQ\Cachet\Console\Commands\InstallCommand; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -35,6 +36,7 @@ class Kernel extends ConsoleKernel BeaconCommand::class, DemoMetricPointSeederCommand::class, DemoSeederCommand::class, + InstallCommand::class, ]; /** From 787986971afd1e572c151d7305e74e995186774c Mon Sep 17 00:00:00 2001 From: James Brooks Date: Mon, 2 Jan 2017 18:37:43 +0000 Subject: [PATCH 2/4] Apply fixes from StyleCI [ci skip] [skip ci] --- app/Console/Commands/InstallCommand.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/Console/Commands/InstallCommand.php b/app/Console/Commands/InstallCommand.php index 870ae1dedde8..1c782333f7ad 100644 --- a/app/Console/Commands/InstallCommand.php +++ b/app/Console/Commands/InstallCommand.php @@ -11,11 +11,7 @@ namespace CachetHQ\Cachet\Console\Commands; -use CachetHQ\Cachet\Bus\Commands\System\Config\UpdateConfigCommand; -use CachetHQ\Cachet\Bus\Jobs\System\SendBeaconJob; -use CachetHQ\Cachet\Composers\SettingsComposer; use CachetHQ\Cachet\Settings\Repository; -use Doctrine\DBAL\Driver\PDOException; use Dotenv\Dotenv; use Dotenv\Exception\InvalidPathException; use Illuminate\Console\Command; From 59d5387b449bfde2d6f3a341e86b41b42f2c969e Mon Sep 17 00:00:00 2001 From: James Brooks Date: Mon, 2 Jan 2017 19:02:52 +0000 Subject: [PATCH 3/4] Remove Repository injection --- app/Console/Commands/InstallCommand.php | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/app/Console/Commands/InstallCommand.php b/app/Console/Commands/InstallCommand.php index 1c782333f7ad..8d5ea372f376 100644 --- a/app/Console/Commands/InstallCommand.php +++ b/app/Console/Commands/InstallCommand.php @@ -11,7 +11,6 @@ namespace CachetHQ\Cachet\Console\Commands; -use CachetHQ\Cachet\Settings\Repository; use Dotenv\Dotenv; use Dotenv\Exception\InvalidPathException; use Illuminate\Console\Command; @@ -37,27 +36,6 @@ class InstallCommand extends Command */ protected $description = 'Install Cachet'; - /** - * The settings repository. - * - * @var \CachetHQ\Cache\Settings\Repository - */ - protected $settings; - - /** - * Create a new demo seeder command instance. - * - * @param \CachetHQ\Cache\Settings\Repository $settings - * - * @return void - */ - public function __construct(Repository $settings) - { - parent::__construct(); - - $this->settings = $settings; - } - /** * Execute the console command. * From 186cbcf8832e582d1620a2975688addb021375aa Mon Sep 17 00:00:00 2001 From: James Brooks Date: Mon, 2 Jan 2017 19:16:55 +0000 Subject: [PATCH 4/4] Add finishing remark --- app/Console/Commands/InstallCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Console/Commands/InstallCommand.php b/app/Console/Commands/InstallCommand.php index 8d5ea372f376..c9df46e0f496 100644 --- a/app/Console/Commands/InstallCommand.php +++ b/app/Console/Commands/InstallCommand.php @@ -56,7 +56,7 @@ public function fire() $this->configureMail(); $this->configureCachet(); - $this->success('Cachet is installed ⚡'); + $this->info('Cachet is installed ⚡'); } /**