Better dep init command

This commit is contained in:
Anton Medvedev 2020-10-16 22:54:20 +02:00
parent f65d013574
commit 10c8b0de8f
8 changed files with 201 additions and 201 deletions

View File

@ -4,7 +4,7 @@
# provision
[Source](/recipe/provision/provision.php)
[Source](/recipe/provision.php)
@ -27,19 +27,19 @@
## Config
### php_version
[Source](/recipe/provision/provision.php#L8)
[Source](/recipe/provision.php#L8)
### sudo_password
[Source](/recipe/provision/provision.php#L9)
[Source](/recipe/provision.php#L9)
## Tasks
### provision
[Source](/recipe/provision/provision.php#L14)
[Source](/recipe/provision.php#L14)
@ -56,57 +56,57 @@ This task is group task which contains next tasks:
### provision:check
[Source](/recipe/provision/provision.php#L33)
[Source](/recipe/provision.php#L33)
### provision:upgrade
[Source](/recipe/provision/provision.php#L54)
[Source](/recipe/provision.php#L54)
### provision:install
[Source](/recipe/provision/provision.php#L60)
[Source](/recipe/provision.php#L60)
### provision:ssh
[Source](/recipe/provision/provision.php#L83)
[Source](/recipe/provision.php#L83)
### provision:user:deployer
[Source](/recipe/provision/provision.php#L97)
[Source](/recipe/provision.php#L97)
### provision:firewall
[Source](/recipe/provision/provision.php#L132)
[Source](/recipe/provision.php#L132)
### provision:install:php
[Source](/recipe/provision/provision.php#L140)
[Source](/recipe/provision.php#L140)
### provision:install:composer
[Source](/recipe/provision/provision.php#L165)
[Source](/recipe/provision.php#L165)
### provision:config:php:sessions
[Source](/recipe/provision/provision.php#L198)
[Source](/recipe/provision.php#L198)
### provision:nginx:dhparam
[Source](/recipe/provision/provision.php#L204)
[Source](/recipe/provision.php#L204)
### provision:nginx
[Source](/recipe/provision/provision.php#L215)
[Source](/recipe/provision.php#L215)

View File

@ -15,6 +15,7 @@
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint">
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification" />
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint" />
</rule>
<file>src/Configuration</file>

View File

@ -18,8 +18,6 @@ require __DIR__ . '/deploy/update_code.php';
require __DIR__ . '/deploy/vendors.php';
require __DIR__ . '/deploy/writable.php';
require __DIR__ . '/provision/provision.php';
use Deployer\Exception\RunException;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\Output;

View File

@ -17,6 +17,7 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;
use function Deployer\Support\fork;
class InitCommand extends Command
{
@ -27,101 +28,186 @@ class InitCommand extends Command
$this
->setName('init')
->setDescription('Initialize deployer in your project')
->addOption('template', 't', InputOption::VALUE_OPTIONAL, 'The template of you project')
->addOption('filepath', null, InputOption::VALUE_OPTIONAL, 'The file path (default "deploy.php")', 'deploy.php');
->addOption('path', 'p', InputOption::VALUE_OPTIONAL, 'Recipe path');
}
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
/** @var FormatterHelper $formatter */
$formatter = $this->getHelper('formatter');
$initializer = new Initializer();
$template = $input->getOption('template');
$filepath = $input->getOption('filepath');
$io = new SymfonyStyle($input, $output);
$recipePath = $input->getOption('path');
if (file_exists($filepath)) {
$output->writeln([
$formatter->formatBlock(
sprintf('The file "%s" already exist.', $filepath),
'bg=red;fg=white', true
),
]);
return 2;
}
$project = 'my_project';
$repository = '';
$hosts = [];
$allow = true;
if ($template === null) {
$io = new SymfonyStyle($input, $output);
// Welcome message
$output->writeln("
_____ _
| __ \ | |
| | | | ___ _ __ | | ___ _ _ ___ _ __
| | | |/ _ \ '_ \| |/ _ \| | | |/ _ \ '__|
| |__| | __/ |_) | | (_) | |_| | __/ |
|_____/ \___| .__/|_|\___/ \__, |\___|_|
| | __/ |
|_| |___/
// Welcome message
$output->write("
\e[38;2;94;231;223m╔\e[39m\e[38;2;95;230;227m╦\e[39m\e[38;2;96;230;230m╗\e[39m\e[38;2;97;226;230m┌\e[39m\e[38;2;98;221;229m─\e[39m\e[38;2;99;217;228m┐\e[39m\e[38;2;100;213;228m┌\e[39m\e[38;2;101;209;227m─\e[39m\e[38;2;102;205;227m┐\e[39m\e[38;2;103;202;226m┬\e[39m \e[38;2;104;198;226m┌\e[39m\e[38;2;105;194;225m─\e[39m\e[38;2;106;191;225m┐\e[39m\e[38;2;107;187;224m┬\e[39m \e[38;2;108;184;224m┬\e[39m\e[38;2;109;180;223m┌\e[39m\e[38;2;110;177;223m─\e[39m\e[38;2;110;174;222m┐\e[39m\e[38;2;111;171;222m┬\e[39m\e[38;2;112;168;221m─\e[39m\e[38;2;113;165;221m┐\e[39m
\e[38;2;114;162;220m║\e[39m\e[38;2;115;159;220m║\e[39m\e[38;2;116;157;219m├\e[39m\e[38;2;117;154;219m┤\e[39m \e[38;2;118;151;218m├\e[39m\e[38;2;119;149;218m─\e[39m\e[38;2;119;147;217m┘\e[39m\e[38;2;120;144;217m│\e[39m \e[38;2;121;142;216m│\e[39m \e[38;2;122;140;216m│\e[39m\e[38;2;123;138;215m└\e[39m\e[38;2;124;136;215m┬\e[39m\e[38;2;125;134;214m┘\e[39m\e[38;2;125;132;214m├\e[39m\e[38;2;126;130;213m┤\e[39m \e[38;2;127;129;213m├\e[39m\e[38;2;129;128;212m┬\e[39m\e[38;2;132;129;212m┘\e[39m
\e[38;2;135;130;211m═\e[39m\e[38;2;138;130;211m╩\e[39m\e[38;2;141;131;210m╝\e[39m\e[38;2;144;132;210m└\e[39m\e[38;2;147;133;209m─\e[39m\e[38;2;150;134;209m┘\e[39m\e[38;2;152;134;208m┴\e[39m \e[38;2;155;135;208m┴\e[39m\e[38;2;158;136;207m─\e[39m\e[38;2;160;137;207m┘\e[39m\e[38;2;162;137;206m└\e[39m\e[38;2;165;138;206m─\e[39m\e[38;2;167;139;205m┘\e[39m \e[38;2;169;140;205m┴\e[39m \e[38;2;171;140;204m└\e[39m\e[38;2;173;141;204m─\e[39m\e[38;2;175;142;203m┘\e[39m\e[38;2;177;143;203m┴\e[39m\e[38;2;178;143;202m└\e[39m\e[38;2;180;144;202m─\e[39m
\e[38;2;94;231;223m█\e[39m\e[38;2;95;230;227m█\e[39m\e[38;2;97;228;230m█\e[39m\e[38;2;98;222;229m█\e[39m\e[38;2;99;217;228m█\e[39m\e[38;2;100;212;228m█\e[39m\e[38;2;102;207;227m█\e[39m\e[38;2;103;202;227m█\e[39m\e[38;2;104;197;226m█\e[39m\e[38;2;105;193;225m█\e[39m\e[38;2;106;188;225m█\e[39m\e[38;2;108;184;224m█\e[39m\e[38;2;109;180;223m█\e[39m\e[38;2;110;176;223m█\e[39m\e[38;2;111;172;222m█\e[39m\e[38;2;112;168;222m█\e[39m\e[38;2;113;164;221m█\e[39m\e[38;2;115;161;220m█\e[39m\e[38;2;116;157;220m█\e[39m\e[38;2;117;154;219m█\e[39m\e[38;2;118;151;218m█\e[39m\e[38;2;119;148;218m█\e[39m\e[38;2;120;145;217m█\e[39m\e[38;2;121;142;216m█\e[39m\e[38;2;122;139;216m█\e[39m\e[38;2;123;137;215m█\e[39m\e[38;2;124;134;215m█\e[39m\e[38;2;126;132;214m█\e[39m\e[38;2;127;130;213m█\e[39m\e[38;2;128;128;213m█\e[39m\e[38;2;132;129;212m█\e[39m\e[38;2;136;130;211m█\e[39m\e[38;2;139;131;211m█\e[39m\e[38;2;143;132;210m█\e[39m\e[38;2;147;133;210m█\e[39m\e[38;2;150;134;209m█\e[39m\e[38;2;153;135;208m█\e[39m\e[38;2;157;136;208m█\e[39m\e[38;2;160;137;207m█\e[39m\e[38;2;163;138;206m█\e[39m\e[38;2;166;138;206m█\e[39m\e[38;2;168;139;205m█\e[39m\e[38;2;171;140;205m█\e[39m\e[38;2;173;141;204m█\e[39m\e[38;2;176;142;203m█\e[39m\e[38;2;178;143;203m█\e[39m\e[38;2;180;144;202m█\e[39m
");
$io->text([
'Welcome to the Deployer config generator.',
'This utility will walk you through creating a deploy.php file.',
'',
'Press ^C at any time to quit.',
]);
$io->text([
'Welcome to the <fg=cyan>Deployer</fg=cyan> config generator.',
'',
'Press ^C at any time to quit.',
]);
// Yes?
$io->confirm('Continue?');
// Yes?
$language = $io->choice('Select recipe language', ['php', 'yaml'], 'php');
if (empty($recipePath)) {
$recipePath = "deploy.$language";
}
// Template
$recipes = $initializer->getRecipes();
$template = $io->choice('Select project template', $recipes, 'common');
// Template
$template = $io->choice('Select project template', $this->recipes(), 'common');
// Repo
$default = false;
try {
$process = Process::fromShellCommandline('git remote get-url origin');
$default = $process->mustRun()->getOutput();
$default = trim($default);
} catch (RuntimeException $e) {
}
$repository = $io->ask('Repository', $default);
// Repo
$default = false;
try {
$process = Process::fromShellCommandline('git remote get-url origin');
$default = $process->mustRun()->getOutput();
$default = trim($default);
} catch (RuntimeException $e) {
}
$repository = $io->ask('Repository', $default);
// Project
$default = false;
try {
$process = Process::fromShellCommandline('basename "$PWD"');
$default = $process->mustRun()->getOutput();
$default = trim($default);
} catch (RuntimeException $e) {
}
$project = $io->ask('Project name', $default);
// Hosts
$host = null;
if (preg_match('/github.com:(?<org>[A-Za-z0-9_\.\-]+)\//', $repository, $m)) {
// Guess host
if (preg_match('/github.com:(?<org>[A-Za-z0-9_.\-]+)\//', $repository, $m)) {
$org = $m['org'];
$tempHostFile = tempnam(sys_get_temp_dir(), 'temp-host-file');
fork(function () use ($org, $tempHostFile) {
try {
['blog' => $blog] = Httpie::get('https://api.github.com/orgs/' . $m['org'])->getJson();
['blog' => $blog] = Httpie::get('https://api.github.com/orgs/' . $org)->getJson();
$host = parse_url($blog, PHP_URL_HOST);
file_put_contents($tempHostFile, $host);
} catch (\Throwable $e) {
// ¯\_(ツ)_/¯
}
}
$hosts = explode(',', $io->ask('Hosts (comma separated)', $host));
});
}
file_put_contents($filepath, $initializer->getTemplate($template, $project, $repository, $hosts, $allow));
// Project
$default = false;
try {
$process = Process::fromShellCommandline('basename "$PWD"');
$default = $process->mustRun()->getOutput();
$default = trim($default);
} catch (RuntimeException $e) {
}
$project = $io->ask('Project name', $default);
// Hosts
$host = null;
if (isset($tempHostFile)) {
$host = file_get_contents($tempHostFile);
}
$hosts = explode(',', $io->ask('Hosts (comma separated)', $host));
file_put_contents($recipePath, $this->$language($template, $project, $repository, $hosts));
$this->telemetry();
$output->writeln(sprintf(
'<info>Successfully created</info> <comment>%s</comment>',
$filepath
$recipePath
));
return 0;
}
private function php(string $template, string $project, string $repository, array $hosts): string
{
$h = "";
foreach ($hosts as $host) {
$h .= "host('{$host}');\n";
}
return <<<PHP
<?php
namespace Deployer;
require 'recipe/$template.php';
require 'recipe/provision.php';
// Config
set('application', '{$project}');
set('deploy_path', '~/{{application}}');
set('repository', '{$repository}');
add('shared_files', []);
add('shared_dirs', []);
add('writable_dirs', []);
// Hosts
{$h}
// Tasks
task('build', function () {
cd('{{release_path}}');
run('npm run build');
});
after('deploy:failed', 'deploy:unlock');
PHP;
}
private function yaml(string $template, string $project, string $repository, array $hosts): string
{
$h = "";
foreach ($hosts as $host) {
$h .= " $host:\n deploy_path: '~/{{application}}'\n";
}
return <<<YAML
import:
- recipe/$template.php
- recipe/provision.php
config:
application: '$project'
repository: '$repository'
shared_files:
- .env
shared_dirs:
- uploads
writable_dirs:
- uploads
hosts:
{$h}
tasks:
build:
script:
- 'cd {{release_path}} && npm run build'
after:
deploy:failed: deploy:unlock
YAML;
}
private function recipes(): array
{
$recipes = [];
$dir = new \DirectoryIterator(__DIR__ . '/../../recipe');
foreach ($dir as $fileinfo) {
if ($fileinfo->isDot()) {
continue;
}
if ($fileinfo->isDir()) {
continue;
}
$recipe = pathinfo($fileinfo->getFilename(), PATHINFO_FILENAME);
if ($recipe === 'README') {
continue;
}
$recipes[] = $recipe;
}
sort($recipes);
return $recipes;
}
}

View File

@ -1,82 +0,0 @@
<?php
/* (c) Anton Medvedev <anton@medv.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Deployer\Component\Initializer;
use function Deployer\cd;
use function Deployer\run;
use function Deployer\task;
class Initializer
{
public function getRecipes()
{
$recipes = [];
$dir = new \DirectoryIterator(__DIR__ . '/../../../recipe');
foreach ($dir as $fileinfo) {
if ($fileinfo->isDot()) {
continue;
}
if ($fileinfo->isDir()) {
continue;
}
$recipe = pathinfo($fileinfo->getFilename(), PATHINFO_FILENAME);
if ($recipe === 'README') {
continue;
}
$recipes[] = $recipe;
}
sort($recipes);
return $recipes;
}
public function getTemplate(string $template, string $project, string $repository, array $hosts, bool $allow): string
{
$h = "";
foreach ($hosts as $host) {
$h .= "host('{$host}');\n";
}
$dontTrack = $allow ? '' : "define('DONT_TRACK', 'ಠ_ಠ');\n";
return <<<PHP
<?php
namespace Deployer;
{$dontTrack}
require 'recipe/$template.php';
// Config
set('application', '{$project}');
set('deploy_path', '~/{{application}}');
set('repository', '{$repository}');
add('shared_files', []);
add('shared_dirs', []);
add('writable_dirs', []);
// Hosts
{$h}
// Tasks
task('deploy:build', function () {
cd('{{release_path}}');
run('npm run build');
});
//after('deploy:update_code', 'deploy:build');
after('deploy:failed', 'deploy:unlock');
PHP;
}
}

View File

@ -147,7 +147,6 @@ class Configuration implements \ArrayAccess
/**
* @param mixed $offset
* @return bool
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint
*/
public function offsetExists($offset)
{

View File

@ -64,24 +64,16 @@ function array_merge_alternate(array $original, array $override)
/**
* Determines if the given string contains the given value.
*
* @param string $haystack
* @param string $needle
* @return bool
*/
function str_contains(string $haystack, string $needle)
function str_contains(string $haystack, string $needle): bool
{
return strpos($haystack, $needle) !== false;
}
/**
* Checks if string stars with given prefix.
*
* @param string $string
* @param string $startString
* @return bool
*/
function starts_with(string $string, string $startString)
function starts_with(string $string, string $startString): bool
{
$len = strlen($startString);
return (substr($string, 0, $len) === $startString);
@ -103,23 +95,17 @@ function env_stringify(array $array): string
/**
* Check if var is closure.
*
* @param $var
* @return bool
* @param mixed $var
*/
function is_closure($var)
function is_closure($var): bool
{
return is_object($var) && ($var instanceof \Closure);
}
/**
* Check if all elements satisfy predicate.
*
* @param array $array
* @param \Closure $predicate
* @return bool
*/
function array_all(array $array, $predicate)
function array_all(array $array, $predicate): bool
{
foreach ($array as $key => $value) {
if (!$predicate($value, $key)) {
@ -131,21 +117,14 @@ function array_all(array $array, $predicate)
/**
* Cleanup CRLF new line endings.
* Issue #2111
*
* @param $string
* @return string
*/
function normalize_line_endings($string)
function normalize_line_endings(string $string): string
{
return str_replace(["\r\n", "\r"], "\n", $string);
}
/**
* Expand leading tilde (~) symbol in given path.
*
* @param string $path
* @return string
*/
function parse_home_dir(string $path): string
{
@ -163,3 +142,22 @@ function parse_home_dir(string $path): string
return $path;
}
function fork(callable $callable)
{
$pid = null;
// Make sure function is not disabled via php.ini "disable_functions"
if (extension_loaded('pcntl') && function_exists('pcntl_fork')) {
declare(ticks = 1);
$pid = pcntl_fork();
}
if (is_null($pid) || $pid === -1) {
// Fork fails or there is no `pcntl` extension.
$callable();
} elseif ($pid === 0) {
// Child process.
posix_setsid();
$callable();
exit(0);
}
}