From a8aad64ab65bc9d4c71383bb4d62d13927ed36b2 Mon Sep 17 00:00:00 2001 From: Kouhei Sano Date: Sun, 4 Apr 2021 17:42:24 +0900 Subject: [PATCH 1/3] refactor: split into command classes --- src/ArchiverCommand.php | 34 -- src/ArchiverInterface.php | 13 - src/ArchiverZip.php | 40 -- src/Color.php | 71 --- src/ColorOutput.php | 50 ++ src/Command/DeployCommand.php | 348 ++++++++++++ src/Command/HelpCommand.php | 51 ++ src/Command/InfoCommand.php | 43 ++ src/Command/InitCommand.php | 46 ++ src/Command/SlackNotificationCommand.php | 58 ++ src/Command/SlackNotificationTestCommand.php | 38 ++ src/Command/UpgradeCommand.php | 44 ++ src/Command/UsageCommand.php | 31 + src/Command/VerifyCommand.php | 36 ++ src/CommandInterface.php | 13 + src/EscapeSequence.php | 114 ++++ src/Main.php | 563 ++----------------- src/Output.php | 46 ++ src/OutputInterface.php | 41 ++ src/{Command.php => Process.php} | 8 +- src/{CommandEvents.php => ProcessEvents.php} | 2 +- src/Slack.php | 9 +- src/{ => Slack}/SlackIncomingResult.php | 2 +- 23 files changed, 1002 insertions(+), 699 deletions(-) delete mode 100644 src/ArchiverCommand.php delete mode 100644 src/ArchiverInterface.php delete mode 100644 src/ArchiverZip.php delete mode 100644 src/Color.php create mode 100644 src/ColorOutput.php create mode 100644 src/Command/DeployCommand.php create mode 100644 src/Command/HelpCommand.php create mode 100644 src/Command/InfoCommand.php create mode 100644 src/Command/InitCommand.php create mode 100644 src/Command/SlackNotificationCommand.php create mode 100644 src/Command/SlackNotificationTestCommand.php create mode 100644 src/Command/UpgradeCommand.php create mode 100644 src/Command/UsageCommand.php create mode 100644 src/Command/VerifyCommand.php create mode 100644 src/CommandInterface.php create mode 100644 src/EscapeSequence.php create mode 100644 src/Output.php create mode 100644 src/OutputInterface.php rename src/{Command.php => Process.php} (94%) rename src/{CommandEvents.php => ProcessEvents.php} (81%) rename src/{ => Slack}/SlackIncomingResult.php (95%) diff --git a/src/ArchiverCommand.php b/src/ArchiverCommand.php deleted file mode 100644 index 3cfe52e..0000000 --- a/src/ArchiverCommand.php +++ /dev/null @@ -1,34 +0,0 @@ -command = $command; - $this->working_directory_path = $working_directory_path; - } - - /** - * @param string $file_path - * - * @return void - */ - public function unarchive($file_path) - { - exec(sprintf('%s "%s" -d "%s"', $this->command, $file_path, $this->working_directory_path)); - } -} diff --git a/src/ArchiverInterface.php b/src/ArchiverInterface.php deleted file mode 100644 index 75cd1c2..0000000 --- a/src/ArchiverInterface.php +++ /dev/null @@ -1,13 +0,0 @@ -working_directory_path = $working_directory_path; - } - - /** - * @param string $file_path - * - * @return void - */ - public function unarchive($file_path) - { - $zip = new ZipArchive(); - $result = $zip->open($file_path); - if ($result !== true) { - echo "open zip file failure.\n"; - $zip->close(); - return; - } - - $zip->extractTo($this->working_directory_path); - $zip->close(); - } -} diff --git a/src/Color.php b/src/Color.php deleted file mode 100644 index f24f5c8..0000000 --- a/src/Color.php +++ /dev/null @@ -1,71 +0,0 @@ - self::RED, - 'cyan' => self::CYAN, - 'purple' => self::PURPLE, - 'black' => self::BLACK, - 'bg-white' => self::BG_WHITE - ]; - - /** - * @param string $color - * @param string $string - * - * @return string - */ - public static function text($color, $string) - { - return sprintf("%s%s\e[0m", static::$colors[$color], $string); - } - - /** - * @param string $text_color - * @param string $bg_color - * @param string $string - * - * @return string - */ - public static function bg_text($text_color, $bg_color, $string) - { - return sprintf("%s%s%s\e[0m", static::$colors[$text_color], static::$colors[$bg_color], $string); - } -} diff --git a/src/ColorOutput.php b/src/ColorOutput.php new file mode 100644 index 0000000..f6b215b --- /dev/null +++ b/src/ColorOutput.php @@ -0,0 +1,50 @@ +apply($text) . PHP_EOL; + } + + /** + * @param string $text + */ + public function warning($text) + { + $escapeSequence = new EscapeSequence('magenta', null, ['bold']); + echo $escapeSequence->apply($text) . PHP_EOL; + } + + /** + * @param string $text + */ + public function info($text) + { + $escapeSequence = new EscapeSequence('cyan', null, ['bold']); + echo $escapeSequence->apply($text) . PHP_EOL; + } + + /** + * @param string $text + */ + public function debug($text) + { + $escapeSequence = new EscapeSequence(null, null, ['underline', 'brink']); + echo $escapeSequence->apply($text) . PHP_EOL; + } +} diff --git a/src/Command/DeployCommand.php b/src/Command/DeployCommand.php new file mode 100644 index 0000000..4b3f145 --- /dev/null +++ b/src/Command/DeployCommand.php @@ -0,0 +1,348 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $configPath = realpath($this->options->getConfig()); + $configure = new Configure($configPath); + + $self = $this; + + if (posix_getpwuid(posix_geteuid())['name'] !== $configure->read('user')) { + $this->output->error('can not executed user.'); + + return; + } + + // GIT + $gitPullLog = null; + if ($this->options->getGit() === 'pull') { + $dir = $configure->read('source.directory'); + if (! is_dir($dir)) { + $this->output->error($dir . ': no such file or directory'); + + return; + } + + // GIT REMOTE SHOW + $checkProcess = Process::define($configure->read('git.path', '/usr/bin/git')); + $checkProcess + ->addArgument('--git-dir', $dir . '.git', '=') + ->addArgument('--work-tree', $dir, '=') + ->addArgument('remote') + ->addArgument('show') + ->addArgument('origin') + ->setSubscribeEvent(ProcessEvents::BEFORE_EXECUTION, function ($command) use ($self) { + /** @var Process $command */ + if ($self->options->hasDebug()) { + $self->output->debug('$ ' . $command->string()); + } + }) + ->execute(); + + if (! $checkProcess->isSuccess()) { + $this->output->plain('$ ' . $checkProcess->string()); + $this->output->error($checkProcess->getOutputString()); + + return; + } + + $this->output->plain('$ ' . $checkProcess->string()); + $this->output->plain($checkProcess->getOutputString()); + + if (strpos($checkProcess->getOutputString(), 'local out of date') === false) { + $this->output->info('the directory is up to date.'); + + return; + } + + // GIT PULL WITH PRUNE + $gitPullProcess = Process::define($configure->read('git.path', '/usr/bin/git')); + $gitPullProcess + ->addArgument('--git-dir', $dir . '.git', '=') + ->addArgument('--work-tree', $dir, '=') + ->addArgument('pull') + ->addArgument('--prune') + ->setSubscribeEvent(ProcessEvents::BEFORE_EXECUTION, function ($command) use ($self) { + /** @var Process $command */ + if ($self->options->hasDebug()) { + $self->output->debug('$ ' . $command->string()); + } + }) + ->execute(); + + if (! $gitPullProcess->isSuccess()) { + $this->output->plain('$ ' . $gitPullProcess->string()); + $this->output->error($gitPullProcess->getOutputString()); + + return; + } + + $this->output->plain('$ ' . $gitPullProcess->string()); + $this->output->info($gitPullProcess->getOutputString()); + + $gitPullLog = $gitPullProcess->getOutputString(); + } + + // FILE SYNC + $syncLog = null; + $isFileChanged = false; + if ($this->options->hasSync()) { + $sync = $this->options->getSync(); + $destinations = $configure->read('destinations'); + foreach ($destinations as $destination) { + $from = $destination['from']; + $to = $destination['to']; + $excludes = isset($destination['excludes']) ? $destination['excludes'] : []; + $scripts = isset($destination['scripts']) ? $destination['scripts'] : []; + + $rsyncProcess = Process::define($configure->read('rsync.path', '/usr/bin/rsync')); + $rsyncProcess + ->addArgument($configure->read('rsync.option')) + ->addArgument($from) + ->addArgument($to) + ->setSubscribeEvent(ProcessEvents::BEFORE_EXECUTION, function ($command) use ($self) { + /** @var Process $command */ + if ($self->options->hasDebug()) { + $self->output->debug('$ ' . $command->string()); + } + }); + + foreach ($excludes as $exclude) { + $rsyncProcess->addArgument('--exclude', $exclude, '='); + } + + $isError = false; + + switch ($sync) { + case 'dry': + $rsyncProcess + ->addArgument('--dry-run') + ->execute(); + if ($rsyncProcess->isSuccess()) { + $this->output->plain('$ ' . $rsyncProcess->string()); + $this->output->info($rsyncProcess->getOutputString()); + } else { + $this->output->plain('$ ' . $rsyncProcess->string()); + $this->output->error($rsyncProcess->getOutputString()); + } + + break; + + case 'force': + $rsyncProcess + ->execute(); + if ($rsyncProcess->isSuccess()) { + $syncLog .= $rsyncProcess->getOutputString(); + $this->output->plain('$ ' . $rsyncProcess->string()); + $this->output->info($rsyncProcess->getOutputString()); + } else { + $isError = true; + $this->output->plain('$ ' . $rsyncProcess->string()); + $this->output->error($rsyncProcess->getOutputString()); + } + + break; + + case 'confirm': + $rsyncDryProcess = clone $rsyncProcess; + + $rsyncDryProcess + ->addArgument('--dry-run') + ->execute(); + if ($rsyncDryProcess->isSuccess()) { + $this->output->plain('$ ' . $rsyncDryProcess->string()); + $this->output->info($rsyncDryProcess->getOutputString()); + } else { + $isError = true; + $this->output->plain('$ ' . $rsyncDryProcess->string()); + $this->output->error($rsyncDryProcess->getOutputString()); + } + + echo 'Do you want to synchronize? [y/N]' . PHP_EOL; + if (trim(fgets(STDIN)) === 'y') { + $rsyncProcess->execute(); + if ($rsyncProcess->isSuccess()) { + $syncLog .= $rsyncProcess->getOutputString(); + $this->output->plain('$ ' . $rsyncProcess->string()); + $this->output->info($rsyncProcess->getOutputString()); + } else { + $isError = true; + $this->output->plain('$ ' . $rsyncProcess->string()); + $this->output->error($rsyncProcess->getOutputString()); + } + } + + break; + } + + if ($sync === 'dry' || $isError) { + continue; + } + + if ($rsyncProcess->getOutput() !== null) { + foreach ($rsyncProcess->getOutput() as $output) { + if (preg_match('/^building file/', $output) === 1 || + preg_match('/^sent \d+ bytes/', $output) === 1 || + preg_match('/^total size/', $output) === 1 || + $output === '') { + continue; + } + + $isFileChanged = true; + } + } + + foreach ($scripts as $script) { + $customScriptProcess = Process::define($script['path']); + $customScriptProcess + ->addArgument($script['option']) + ->setSubscribeEvent(ProcessEvents::BEFORE_EXECUTION, function ($command) use ($self) { + /** @var Process $command */ + if ($self->options->hasDebug()) { + $self->output->debug('$ ' . $command->string()); + } + }) + ->execute(); + + if ($customScriptProcess->isSuccess()) { + $this->output->info($customScriptProcess->path() . ': ' . $customScriptProcess->getOutputString()); + } else { + $this->output->error($customScriptProcess->getOutputString()); + } + } + } + } + + // FILE CHANGE NOTIFICATION + if (! $isFileChanged) { + return; + } + + $message = new SlackMessage(); + $message + ->addBlock( + new SlackHeader(new SlackPlainText('Deploy successful')) + ) + ->addBlock( + (new SlackSection())->setText( + new SlackPlainText(get_current_user() . ' was deployed :simple_smile:') + ) + ) + ->addBlock( + (new SlackSection()) + ->addField( + new SlackMarkdownText('*Hostname:*' . PHP_EOL . gethostname()) + ) + ->addField( + new SlackMarkdownText('*URL:*' . PHP_EOL . $configure->read('url')) + ) + ); + + if ($gitPullLog !== null) { + $message + ->addBlock( + new SlackDivider() + ) + ->addBlock( + (new SlackSection()) + ->addField( + new SlackMarkdownText('*Git pull*') + ) + ); + + $chunks = str_split($gitPullLog, SlackSection::TEXT_MAX_LENGTH - 6); + foreach ($chunks as $chunk) { + $message + ->addBlock( + (new SlackSection()) + ->setText( + new SlackMarkdownText('```' . $chunk . '```') + ) + ); + } + } + + if ($syncLog !== null) { + $message + ->addBlock( + new SlackDivider() + ) + ->addBlock( + (new SlackSection()) + ->addField( + new SlackMarkdownText('*Rsync*') + ) + ); + + $chunks = str_split($syncLog, SlackSection::TEXT_MAX_LENGTH - 6); + foreach ($chunks as $chunk) { + $message + ->addBlock( + (new SlackSection()) + ->setText( + new SlackMarkdownText('```' . $chunk . '```') + ) + ); + } + } + + $message + ->addBlock( + new SlackDivider() + ) + ->addBlock( + (new SlackContext()) + ->addElement( + new SlackMarkdownText('Date: ' . date("Y/m/d H:i:s")) + ) + ->addElement( + new SlackMarkdownText('Version: ' . Main::appName() . ' ' . Main::VERSION) + ) + ->addElement( + new SlackMarkdownText('Configuration: ' . $configure->getConfigPath()) + ) + ); + + $slack = new Slack( + $configure->read('slack.incomingWebhook'), + $configure->read('slack.channel'), + $configure->read('slack.username') + ); + $slackResult = $slack->send($message); + if (! $slackResult->isOk()) { + $this->output->error($slackResult->getError()); + } + } +} diff --git a/src/Command/HelpCommand.php b/src/Command/HelpCommand.php new file mode 100644 index 0000000..852aa42 --- /dev/null +++ b/src/Command/HelpCommand.php @@ -0,0 +1,51 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $rocket = Main::VERSION; + + $content = <<output->plain($content); + } +} diff --git a/src/Command/InfoCommand.php b/src/Command/InfoCommand.php new file mode 100644 index 0000000..913a096 --- /dev/null +++ b/src/Command/InfoCommand.php @@ -0,0 +1,43 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $uname = php_uname(); + $binary = PHP_BINARY; + $version = PHP_VERSION; + $ini = php_ini_loaded_file(); + $rocket = MAIN::VERSION; + + $content = <<output->plain($content); + } +} diff --git a/src/Command/InitCommand.php b/src/Command/InitCommand.php new file mode 100644 index 0000000..58515cd --- /dev/null +++ b/src/Command/InitCommand.php @@ -0,0 +1,46 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $templateName = $this->options->getInit(); + + $content = null; + if ($templateName === 'cakephp3') { + $content = file_get_contents(__DIR__ . '/../config/cakephp3.json'); + } + + if ($templateName === 'eccube4') { + $content = file_get_contents(__DIR__ . '/../config/eccube4.json'); + } + + if ($templateName === 'wordpress') { + $content = file_get_contents(__DIR__ . '/../config/wordpress.json'); + } + + if ($content === null) { + $content = file_get_contents(__DIR__ . '/../config/plain.json'); + } + + $this->output->plain($content); + } +} diff --git a/src/Command/SlackNotificationCommand.php b/src/Command/SlackNotificationCommand.php new file mode 100644 index 0000000..64283e4 --- /dev/null +++ b/src/Command/SlackNotificationCommand.php @@ -0,0 +1,58 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $configPath = realpath($this->options->getConfig()); + $configure = new Configure($configPath); + + $lines = []; + while ($line = fgets(STDIN)) { + $lines[] = trim($line); + } + + $message = new SlackMessage(); + + $chunks = str_split(implode(PHP_EOL, $lines), SlackSection::TEXT_MAX_LENGTH - 6); + foreach ($chunks as $chunk) { + $message + ->addBlock( + (new SlackSection()) + ->setText( + new SlackMarkdownText('```' . $chunk . '```') + ) + ); + } + + $slack = new Slack( + $configure->read('slack.incomingWebhook'), + $configure->read('slack.channel'), + $configure->read('slack.username') + ); + $slack->send($message); + } +} diff --git a/src/Command/SlackNotificationTestCommand.php b/src/Command/SlackNotificationTestCommand.php new file mode 100644 index 0000000..1c57624 --- /dev/null +++ b/src/Command/SlackNotificationTestCommand.php @@ -0,0 +1,38 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $configPath = realpath($this->options->getConfig()); + $configure = new Configure($configPath); + + $slack = new Slack( + $configure->read('slack.incomingWebhook'), + $configure->read('slack.channel'), + $configure->read('slack.username') + ); + + $slack->test($configure); + } +} diff --git a/src/Command/UpgradeCommand.php b/src/Command/UpgradeCommand.php new file mode 100644 index 0000000..ab96e36 --- /dev/null +++ b/src/Command/UpgradeCommand.php @@ -0,0 +1,44 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $working_directory_path = sys_get_temp_dir() . '/' . 'rocket-' . substr(str_shuffle('1234567890abcdefghijklmnopqrstuvwxyz'), + 0, 8); + if (! mkdir($working_directory_path) && ! is_dir($working_directory_path)) { + $this->output->error(sprintf('Directory "%s" was not created.', $working_directory_path)); + + return; + } + + $updater = new Updater($working_directory_path); + $result = $updater->upgrade(); + if (! $result->isOk()) { + $this->output->error($result->getError()); + + return; + } + + $this->output->info('New version: ' . $result->getFilePath()); + } +} diff --git a/src/Command/UsageCommand.php b/src/Command/UsageCommand.php new file mode 100644 index 0000000..fdea629 --- /dev/null +++ b/src/Command/UsageCommand.php @@ -0,0 +1,31 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $content = <<output->warning($content); + } +} diff --git a/src/Command/VerifyCommand.php b/src/Command/VerifyCommand.php new file mode 100644 index 0000000..b5f719e --- /dev/null +++ b/src/Command/VerifyCommand.php @@ -0,0 +1,36 @@ +options = $options; + $this->output = $output; + } + + public function execute() + { + $configPath = realpath($this->options->getConfig()); + + if (Configure::verify($configPath)) { + $this->output->info($configPath . ': OK'); + + return; + } + + $this->output->error($configPath . ': NG'); + } +} diff --git a/src/CommandInterface.php b/src/CommandInterface.php new file mode 100644 index 0000000..a969d2b --- /dev/null +++ b/src/CommandInterface.php @@ -0,0 +1,13 @@ + self::FOREGROUND_BLACK, + 'white' => self::FOREGROUND_WHITE, + 'red' => self::FOREGROUND_RED, + 'cyan' => self::FOREGROUND_CYAN, + 'magenta' => self::FOREGROUND_MAGENTA, + 'bg-white' => self::BACKGROUND_WHITE, + ]; + + const OPTIONS = [ + 'bold' => self::BOLD, + 'underline' => self::UNDERLINE, + 'brink' => self::BRINK, + ]; + + /** @var string|null */ + private $foreground; + + /** @var string|null */ + private $background; + + /** @var array */ + private $options; + + /** + * @param string|null $foreground + * @param string|null $background + * @param array $options + */ + public function __construct($foreground, $background = null, array $options = []) + { + $this->foreground = $foreground; + $this->background = $background; + $this->options = $options; + } + + /** + * @param string $text + * + * @return string + */ + public function apply($text) + { + $format = ''; + $values = []; + + if ($this->foreground !== null) { + $format .= '%s'; + $values[] = self::COLORS[$this->foreground]; + } + + if ($this->background !== null) { + $format .= '%s'; + $values[] = self::COLORS[$this->background]; + } + + if (! empty($this->options)) { + $optionCodes = []; + foreach ($this->options as $option) { + $optionCodes[] = self::OPTIONS[$option]; + } + + if (! empty($optionCodes)) { + $format .= '%s'; + $values[] = implode(';', $optionCodes); + } + } + + if (empty($values)) { + return $text; + } + + $format .= '%s%s'; + $values[] = $text; + $values[] = self::RESET; + + return vsprintf($format, $values); + } +} diff --git a/src/Main.php b/src/Main.php index c9b4b85..d571bbc 100644 --- a/src/Main.php +++ b/src/Main.php @@ -3,14 +3,15 @@ namespace Rocket; use Phar; -use Rocket\Slack\BlockKit\Block\Context as SlackContext; -use Rocket\Slack\BlockKit\Block\Divider as SlackDivider; -use Rocket\Slack\BlockKit\Block\Header as SlackHeader; -use Rocket\Slack\BlockKit\Block\Section as SlackSection; -use Rocket\Slack\BlockKit\Element\MarkdownText as SlackMarkdownText; -use Rocket\Slack\BlockKit\Element\PlainText as SlackPlainText; -use Rocket\Slack\BlockKit\Message; -use Rocket\Slack\BlockKit\Message as SlackMessage; +use Rocket\Command\DeployCommand; +use Rocket\Command\HelpCommand; +use Rocket\Command\InfoCommand; +use Rocket\Command\InitCommand; +use Rocket\Command\SlackNotificationCommand; +use Rocket\Command\SlackNotificationTestCommand; +use Rocket\Command\UpgradeCommand; +use Rocket\Command\UsageCommand; +use Rocket\Command\VerifyCommand; class Main { @@ -29,404 +30,52 @@ public function __construct($options) public function run() { - // INIT - if ($this->options->hasInit()) { - $this->printConfig($this->options->getInit()); + $output = $this->options->hasNoColor() ? new Output() : new ColorOutput(); - return; - } + $command = null; - // INFO if ($this->options->hasInfo()) { - $this->printInfo(); - - return; + $command = new InfoCommand($this->options, $output); } - // HELP if ($this->options->hasHelp()) { - $this->printHelp(); - - return; - } - - // UPGRADE - if ($this->options->hasUpgrade()) { - $this->upgrade(); - - return; - } - - // CONFIGURE - if (! $this->options->hasConfig()) { - $this->printUsage(); - - return; - } - - $config_path = realpath($this->options->getConfig()); - if (! file_exists($config_path)) { - $this->printInit(); - - return; - } - - if ($this->options->hasVerify()) { - if (Configure::verify($config_path)) { - $this->info($config_path . ': OK'); - } else { - $this->error($config_path . ': NG'); - } - - return; + $command = new HelpCommand($this->options, $output); } - $configure = new Configure($config_path); - $self = $this; - - // NOTIFICATION - if ($this->options->hasNotify()) { - $lines = []; - while ($line = fgets(STDIN)) { - $lines[] = trim($line); - } - - $message = new Message(); - - $chunks = str_split(implode(PHP_EOL, $lines), SlackSection::TEXT_MAX_LENGTH - 6); - foreach ($chunks as $chunk) { - $message - ->addBlock( - (new SlackSection()) - ->setText( - new SlackMarkdownText('```' . $chunk . '```') - ) - ); - } - - $slack = new Slack( - $configure->read('slack.incomingWebhook'), - $configure->read('slack.channel'), - $configure->read('slack.username') - ); - $slack->send($message); - - return; - } - - // USER CHECK - if (posix_getpwuid(posix_geteuid())['name'] !== $configure->read('user')) { - $this->error('can not executed user.'); - - return; - } - - // NOTIFICATION TEST - if ($this->options->hasNotifyTest()) { - $slack = new Slack( - $configure->read('slack.incomingWebhook'), - $configure->read('slack.channel'), - $configure->read('slack.username') - ); - $slackResult = $slack->test($configure); - if (! $slackResult->isOk()) { - $this->error($slackResult->getError()); - } - - return; + if ($this->options->hasInit()) { + $command = new InitCommand($this->options, $output); } - // GIT - $git_pull_log = null; - if ($this->options->getGit() === 'pull') { - $directory_path = $configure->read('source.directory'); - if (! is_dir($directory_path)) { - $this->printNotfoundPath($directory_path); - - return; - } - - // CHECK - $command = Command::define($configure->read('git.path', '/usr/bin/git')); - $command - ->addArgument('--git-dir', $directory_path . '.git', '=') - ->addArgument('--work-tree', $directory_path, '=') - ->addArgument('remote') - ->addArgument('show') - ->addArgument('origin') - ->setSubscribeEvent(CommandEvents::BEFORE_EXECUTION, function ($command) use ($self) { - /** @var Command $command */ - if ($self->options->hasDebug()) { - $self->debug('$ ' . $command->string()); - } - }) - ->execute(); - if ($command->isSuccess()) { - $this->info('> ' . $command->string()); - $this->info($command->getOutputString()); - } else { - $this->info('> ' . $command->string()); - $this->error($command->getOutputString()); - - return; - } - - if (strpos($command->getOutputString(), 'local out of date') === false) { - return; - } - - // PULL WITH PRUNE - $command = Command::define($configure->read('git.path', '/usr/bin/git')); - $command - ->addArgument('--git-dir', $directory_path . '.git', '=') - ->addArgument('--work-tree', $directory_path, '=') - ->addArgument('pull') - ->addArgument('--prune') - ->setSubscribeEvent(CommandEvents::BEFORE_EXECUTION, function ($command) use ($self) { - /** @var Command $command */ - if ($self->options->hasDebug()) { - $self->debug('$ ' . $command->string()); - } - }) - ->execute(); - - if ($command->isSuccess()) { - $this->info('> ' . $command->string()); - $this->info($command->getOutputString()); - } else { - $this->error('> ' . $command->string()); - $this->error($command->getOutputString()); - - return; - } - - $git_pull_log = $command->getOutputString(); + if ($this->options->hasUpgrade()) { + $command = new UpgradeCommand($this->options, $output); } - // SYNC - $sync_log = null; - $is_file_changed = false; - if ($this->options->hasSync()) { - $sync = $this->options->getSync(); - $destinations = $configure->read('destinations'); - foreach ($destinations as $destination) { - $from = $destination['from']; - $to = $destination['to']; - $excludes = isset($destination['excludes']) ? $destination['excludes'] : []; - $scripts = isset($destination['scripts']) ? $destination['scripts'] : []; - - $command = Command::define($configure->read('rsync.path', '/usr/bin/rsync')); - $command - ->addArgument($configure->read('rsync.option')) - ->addArgument($from) - ->addArgument($to) - ->setSubscribeEvent(CommandEvents::BEFORE_EXECUTION, function ($command) use ($self) { - /** @var Command $command */ - if ($self->options->hasDebug()) { - $self->debug('$ ' . $command->string()); - } - }); - - foreach ($excludes as $exclude) { - $command->addArgument('--exclude', $exclude, '='); - } - - $error = false; - - switch ($sync) { - case 'dry': - $command - ->addArgument('--dry-run') - ->execute(); - if ($command->isSuccess()) { - $this->info('> rsync dry'); - $this->info($command->getOutputString()); - } else { - $this->error('> rsync'); - $this->error($command->getOutputString()); - } - - break; - case 'force': - $command - ->execute(); - if ($command->isSuccess()) { - $sync_log .= $command->getOutputString(); - $this->info('> rsync'); - $this->info($command->getOutputString()); - } else { - $error = true; - $this->error('> rsync'); - $this->error($command->getOutputString()); - } - - break; - case 'confirm': - $_command = clone $command; - - $command - ->addArgument('--dry-run') - ->execute(); - if ($command->isSuccess()) { - //$sync_log .= $command->getOutputString(); - $this->info('> rsync dry'); - $this->info($command->getOutputString()); - } else { - $error = true; - $this->error('> rsync'); - $this->error($command->getOutputString()); - } - - echo 'Do you want to synchronize? [y/N]' . PHP_EOL; - if (trim(fgets(STDIN)) === 'y') { - $_command->execute(); - if ($_command->isSuccess()) { - $sync_log .= $_command->getOutputString(); - $this->info('> rsync'); - $this->info($_command->getOutputString()); - } else { - $error = true; - $this->error('> rsync'); - $this->error($_command->getOutputString()); - } - } - - break; + if ($this->options->hasConfig()) { + $configPath = realpath($this->options->getConfig()); + if (file_exists($configPath)) { + if ($this->options->hasVerify()) { + $command = new VerifyCommand($this->options, $output); } - if ($sync === 'dry' || $error) { - continue; + if ($this->options->hasNotify()) { + $command = new SlackNotificationCommand($this->options, $output); } - foreach ($command->getOutput() as $output) { - if (preg_match('/^building file/', $output) === 1 || - preg_match('/^sent \d+ bytes/', $output) === 1 || - preg_match('/^total size/', $output) === 1 || - $output === '') { - continue; - } - - $is_file_changed = true; + if ($this->options->hasNotifyTest()) { + $command = new SlackNotificationTestCommand($this->options, $output); } - foreach ($scripts as $script) { - $command = Command::define($script['path']); - $command - ->addArgument($script['option']) - ->setSubscribeEvent(CommandEvents::BEFORE_EXECUTION, function ($command) use ($self) { - /** @var Command $command */ - if ($self->options->hasDebug()) { - $self->debug('$ ' . $command->string()); - } - }) - ->execute(); - - if ($command->isSuccess()) { - $this->info($command->path() . ': ' . $command->getOutputString()); - } else { - $this->error($command->getOutputString()); - } + if ($command === null) { + $command = new DeployCommand($this->options, $output); } } } - // NOTIFICATION - if ($is_file_changed) { - $message = new SlackMessage(); - $message - ->addBlock( - new SlackHeader(new SlackPlainText('Deploy successful')) - ) - ->addBlock( - (new SlackSection())->setText( - new SlackPlainText(get_current_user() . ' was deployed :simple_smile:') - ) - ) - ->addBlock( - (new SlackSection()) - ->addField( - new SlackMarkdownText('*Hostname:*' . PHP_EOL . gethostname()) - ) - ->addField( - new SlackMarkdownText('*URL:*' . PHP_EOL . $configure->read('url')) - ) - ); - - if ($git_pull_log !== null) { - $message - ->addBlock( - new SlackDivider() - ) - ->addBlock( - (new SlackSection()) - ->addField( - new SlackMarkdownText('*Git pull*') - ) - ); - - $chunks = str_split($git_pull_log, SlackSection::TEXT_MAX_LENGTH - 6); - foreach ($chunks as $chunk) { - $message - ->addBlock( - (new SlackSection()) - ->setText( - new SlackMarkdownText('```' . $chunk . '```') - ) - ); - } - } - - if ($sync_log !== null) { - $message - ->addBlock( - new SlackDivider() - ) - ->addBlock( - (new SlackSection()) - ->addField( - new SlackMarkdownText('*Rsync*') - ) - ); - - $chunks = str_split($sync_log, SlackSection::TEXT_MAX_LENGTH - 6); - foreach ($chunks as $chunk) { - $message - ->addBlock( - (new SlackSection()) - ->setText( - new SlackMarkdownText('```' . $chunk . '```') - ) - ); - } - } - - $message - ->addBlock( - new SlackDivider() - ) - ->addBlock( - (new SlackContext()) - ->addElement( - new SlackMarkdownText('Date: ' . date("Y/m/d H:i:s")) - ) - ->addElement( - new SlackMarkdownText('Version: ' . self::appName() . ' ' . self::VERSION) - ) - ->addElement( - new SlackMarkdownText('Configuration: ' . $configure->getConfigPath()) - ) - ); - - $slack = new Slack( - $configure->read('slack.incomingWebhook'), - $configure->read('slack.channel'), - $configure->read('slack.username') - ); - $slackResult = $slack->send($message); - if (! $slackResult->isOk()) { - $this->error($slackResult->getError()); - } + if ($command === null) { + $command = new UsageCommand($this->options, $output); } + + $command->execute(); } /** @@ -441,152 +90,4 @@ public static function appName() return $name; } - - private function upgrade() - { - $working_directory_path = sys_get_temp_dir() . '/' . 'rocket-' . substr(str_shuffle('1234567890abcdefghijklmnopqrstuvwxyz'), - 0, 8); - if (! mkdir($working_directory_path) && ! is_dir($working_directory_path)) { - $this->error(sprintf('Directory "%s" was not created.', $working_directory_path)); - - return; - } - -// $archiver = $this->options->hasUnzip() ? -// new ArchiverCommand($this->options->getUnzip(), $working_directory_path) : -// new ArchiverZip($working_directory_path); - - $updater = new Updater($working_directory_path); - $result = $updater->upgrade(); - if (! $result->isOk()) { - $this->error($result->getError()); - - return; - } - - $this->info('New version: ' . $result->getFilePath()); - } - - private function printInfo() - { - echo 'OS: ' . php_uname() . PHP_EOL; - echo 'PHP binary: ' . PHP_BINARY . PHP_EOL; - echo 'PHP version: ' . PHP_VERSION . PHP_EOL; - echo 'php.ini used: ' . php_ini_loaded_file() . PHP_EOL; - echo 'rocket version: ' . self::VERSION . PHP_EOL; - } - - private function printHelp() - { - echo 'rocket.phar ' . self::VERSION . PHP_EOL; - echo PHP_EOL; - echo 'Usage:' . PHP_EOL; - echo './rocket.phar [options]' . PHP_EOL; - echo PHP_EOL; - echo 'Options:' . PHP_EOL; - echo ' -c, --config {file name} Configuration file name as JSON' . PHP_EOL; - echo ' -g, --git [pull] Git operation' . PHP_EOL; - echo ' -h, --help Display this help message' . PHP_EOL; - echo ' -i, --init [plain|cakephp3|eccube4|wordpress] Print sample configuration file' . PHP_EOL; - echo ' -n, --notify Simple slack notification' . PHP_EOL; - echo ' --notify-test Slack notification test' . PHP_EOL; - echo ' --no-color Without color' . PHP_EOL; - echo ' -s, --sync [dry|confirm|force] Rsync operation' . PHP_EOL; - echo ' -u, --upgrade Download new version file' . PHP_EOL; - echo ' --unzip {path} Using zip command on upgrade' . PHP_EOL; - echo ' -v, --verify Verify configuration file' . PHP_EOL; - } - - /** - * @var string $template - */ - private function printConfig($template) - { - if ($template === 'cakephp3') { - echo file_get_contents(__DIR__ . '/config/cakephp3.json') . PHP_EOL; - - return; - } - - if ($template === 'eccube4') { - echo file_get_contents(__DIR__ . '/config/eccube4.json') . PHP_EOL; - - return; - } - - if ($template === 'wordpress') { - echo file_get_contents(__DIR__ . '/config/wordpress.json') . PHP_EOL; - - return; - } - - echo file_get_contents(__DIR__ . '/config/plain.json') . PHP_EOL; - } - - private function printUsage() - { - $this->warning('Usage: ./rocket.phar --config ./rocket.json --git [pull] --sync [dry|confirm|force]'); - } - - private function printInit() - { - $this->warning('Usage: ./rocket.phar --init > ./rocket.json'); - } - - /** - * @param string $path - */ - private function printNotfoundPath($path) - { - $this->error($path . ': No such file or directory'); - } - - /** - * @param string $reason - */ - private function error($reason) - { - $string = self::appName() . ': ' . $reason; - if ($this->options->hasNoColor()) { - echo $string . PHP_EOL; - } else { - echo Color::text('red', $string) . PHP_EOL; - } - } - - /** - * @param string $text - */ - private function warning($text) - { - if ($this->options->hasNoColor()) { - echo $text . PHP_EOL; - } else { - echo Color::text('purple', $text) . PHP_EOL; - } - } - - /** - * @param string $text - */ - private function info($text) - { - if ($this->options->hasNoColor()) { - echo $text . PHP_EOL; - } else { - echo Color::text('cyan', $text) . PHP_EOL; - } - } - - /** - * @param string $text - */ - private function debug($text) - { - if ($this->options->hasNoColor()) { - echo $text . PHP_EOL; - } else { - echo Color::bg_text('black', 'bg-white', $text) . PHP_EOL; - } - } } diff --git a/src/Output.php b/src/Output.php new file mode 100644 index 0000000..0819511 --- /dev/null +++ b/src/Output.php @@ -0,0 +1,46 @@ +build(); - if (isset($this->events[CommandEvents::BEFORE_EXECUTION])) { - $callable = $this->events[CommandEvents::BEFORE_EXECUTION]; + if (isset($this->events[ProcessEvents::BEFORE_EXECUTION])) { + $callable = $this->events[ProcessEvents::BEFORE_EXECUTION]; $callable($this); } diff --git a/src/CommandEvents.php b/src/ProcessEvents.php similarity index 81% rename from src/CommandEvents.php rename to src/ProcessEvents.php index ac8e047..f0b19c6 100644 --- a/src/CommandEvents.php +++ b/src/ProcessEvents.php @@ -2,7 +2,7 @@ namespace Rocket; -class CommandEvents +class ProcessEvents { const BEFORE_EXECUTION = 'command.before_execution'; } diff --git a/src/Slack.php b/src/Slack.php index c87d232..42a59bd 100644 --- a/src/Slack.php +++ b/src/Slack.php @@ -10,6 +10,7 @@ use Rocket\Slack\BlockKit\Element\MarkdownText; use Rocket\Slack\BlockKit\Element\PlainText; use Rocket\Slack\BlockKit\Message; +use Rocket\Slack\SlackIncomingResult; class Slack { @@ -113,13 +114,13 @@ public function test($configure) ) ->addBlock( (new Section()) - ->addField( + ->setText( new MarkdownText('*Git pull*') ) ) ->addBlock( (new Section()) - ->addField( + ->setText( new MarkdownText('```HELLO WORLD```') ) ) @@ -128,13 +129,13 @@ public function test($configure) ) ->addBlock( (new Section()) - ->addField( + ->setText( new MarkdownText('*Rsync*') ) ) ->addBlock( (new Section()) - ->addField( + ->setText( new MarkdownText('```HELLO WORLD```') ) ) diff --git a/src/SlackIncomingResult.php b/src/Slack/SlackIncomingResult.php similarity index 95% rename from src/SlackIncomingResult.php rename to src/Slack/SlackIncomingResult.php index 3faa07a..e10aeee 100644 --- a/src/SlackIncomingResult.php +++ b/src/Slack/SlackIncomingResult.php @@ -1,6 +1,6 @@ Date: Sun, 4 Apr 2021 18:17:22 +0900 Subject: [PATCH 2/3] feat: chunker --- src/Chunker.php | 44 ++++++++++++++++++++++++ src/Command/DeployCommand.php | 7 ++-- src/Command/SlackNotificationCommand.php | 9 +++-- 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/Chunker.php diff --git a/src/Chunker.php b/src/Chunker.php new file mode 100644 index 0000000..b4afa74 --- /dev/null +++ b/src/Chunker.php @@ -0,0 +1,44 @@ + + */ + public function __invoke($text, $length) + { + $chunks = []; + $buf = null; + + $lines = explode(PHP_EOL, $text); + foreach ($lines as $line) { + if (strlen($line) >= $length) { + foreach (str_split($line, $length) as $chunk) { + $chunks[] = $chunk; + } + + continue; + } + + $line .= PHP_EOL; + + if (strlen($buf . $line) > $length) { + $chunks[] = $buf; + $buf = null; + } + + $buf .= $line; + } + + if ($buf !== null) { + $chunks[] = $buf; + } + + return $chunks; + } +} diff --git a/src/Command/DeployCommand.php b/src/Command/DeployCommand.php index 4b3f145..c521697 100644 --- a/src/Command/DeployCommand.php +++ b/src/Command/DeployCommand.php @@ -2,6 +2,7 @@ namespace Rocket\Command; +use Rocket\Chunker; use Rocket\CommandInterface; use Rocket\Configure; use Rocket\Main; @@ -37,6 +38,8 @@ public function execute() $configPath = realpath($this->options->getConfig()); $configure = new Configure($configPath); + $chunker = new Chunker(); + $self = $this; if (posix_getpwuid(posix_geteuid())['name'] !== $configure->read('user')) { @@ -282,7 +285,7 @@ public function execute() ) ); - $chunks = str_split($gitPullLog, SlackSection::TEXT_MAX_LENGTH - 6); + $chunks = $chunker($gitPullLog, SlackSection::TEXT_MAX_LENGTH - 6); foreach ($chunks as $chunk) { $message ->addBlock( @@ -306,7 +309,7 @@ public function execute() ) ); - $chunks = str_split($syncLog, SlackSection::TEXT_MAX_LENGTH - 6); + $chunks = $chunker($syncLog, SlackSection::TEXT_MAX_LENGTH - 6); foreach ($chunks as $chunk) { $message ->addBlock( diff --git a/src/Command/SlackNotificationCommand.php b/src/Command/SlackNotificationCommand.php index 64283e4..7d0e043 100644 --- a/src/Command/SlackNotificationCommand.php +++ b/src/Command/SlackNotificationCommand.php @@ -2,6 +2,7 @@ namespace Rocket\Command; +use Rocket\Chunker; use Rocket\CommandInterface; use Rocket\Configure; use Rocket\Options; @@ -30,14 +31,16 @@ public function execute() $configPath = realpath($this->options->getConfig()); $configure = new Configure($configPath); - $lines = []; + $content = null; while ($line = fgets(STDIN)) { - $lines[] = trim($line); + $content .= $line; } $message = new SlackMessage(); - $chunks = str_split(implode(PHP_EOL, $lines), SlackSection::TEXT_MAX_LENGTH - 6); + $chunker = new Chunker(); + $chunks = $chunker($content, SlackSection::TEXT_MAX_LENGTH - 6); + foreach ($chunks as $chunk) { $message ->addBlock( From a7e27e243cfbe49e5e25f9ebcfac524ea885d9ff Mon Sep 17 00:00:00 2001 From: Kouhei Sano Date: Mon, 5 Apr 2021 08:26:53 +0900 Subject: [PATCH 3/3] feat: chunker --- src/Command/SlackNotificationCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/SlackNotificationCommand.php b/src/Command/SlackNotificationCommand.php index 7d0e043..6c2ebcd 100644 --- a/src/Command/SlackNotificationCommand.php +++ b/src/Command/SlackNotificationCommand.php @@ -46,7 +46,7 @@ public function execute() ->addBlock( (new SlackSection()) ->setText( - new SlackMarkdownText('```' . $chunk . '```') + new SlackMarkdownText($chunk) ) ); }