Skip to content

Commit

Permalink
Improved existing dashboard functionality and implemented deploy scri…
Browse files Browse the repository at this point in the history
…pt view/edit per client
  • Loading branch information
kg-bot committed Jun 23, 2018
1 parent 657cf41 commit da2697c
Show file tree
Hide file tree
Showing 14 changed files with 531 additions and 134 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"php": ">=7.1",
"ddtraceweb/monolog-parser": "^1.2",
"kg-bot/laravel-localization-to-vue": "1.*",
"laravel/framework": "5.*"
"laravel/framework": "5.*",
"predis/predis": "^1.1"
},
"keywords": [
"laravel",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"vue-spinner": "^1.0.3",
"vue-toasted": "^1.1.24",
"vue2-dropzone": "^3.1.0",
"vuejs-datepicker": "^0.9.29"
"vuejs-datepicker": "^0.9.29",
"vuex": "^3.0.1"
}
}
19 changes: 16 additions & 3 deletions routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
Route::group( [

'prefix' => config( 'laravel-deploy.routes.prefix' ) . '/ajax',
'middleware' => array_merge( [ 'web' ], config( 'laravel-deploy.front.routes.ajax.middleware' ) ),
'middleware' => array_merge( [ 'web', 'auth' ], config( 'laravel-deploy.front.routes.ajax.middleware' ) ),
'namespace' => config( 'laravel-deploy.front.routes.ajax.namespace' ),
], function () {

Expand Down Expand Up @@ -71,7 +71,20 @@
/**
* Deployments routes
*/
Route::post( 'deploy/now/{client}', 'SettingsController@deployNow' )
->name( 'laravel-deploy.ajax.settings.deployments.deploy_now' );
Route::group( [ 'prefix' => 'deployments' ], function () {

Route::post( 'deploy/now/{client}', 'SettingsController@deployNow' )
->name( 'laravel-deploy.ajax.settings.deployments.deploy_now' );

/**
* Deployment script routes
*/
Route::get( 'scripts/{client}', 'ClientScriptController@fetch' )
->name( 'laravel-deploy.ajax.settings.deployments.scripts.fetch' );

Route::post( 'scripts/{client}', 'ClientScriptController@save' )
->name( 'laravel-deploy.ajax.settings.deployments.scripts.save' );
} );

} );
} );
51 changes: 51 additions & 0 deletions src/Http/Controllers/Front/Ajax/ClientScriptController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace KgBot\LaravelDeploy\Http\Controllers\Front\Ajax;

use Illuminate\Http\Request;
use KgBot\LaravelDeploy\Http\Controllers\BaseController;
use KgBot\LaravelDeploy\Models\Client;
use League\Flysystem\FileNotFoundException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class ClientScriptController extends BaseController
{
public function fetch( Client $client )
{
$filepath = base_path( DIRECTORY_SEPARATOR . $client->script_source );

if ( file_exists( $filepath ) ) {

$content = file_get_contents( $filepath );

return response()->json( compact( 'content' ) );

} else {

throw new FileNotFoundException( 'We can\'t find deploy script defined for this client' );
}
}

public function save( Client $client, Request $request )
{
if ( $request->has( 'content' ) && $content = $request->get( 'content' ) ) {

$filepath = base_path( DIRECTORY_SEPARATOR . $client->script_source );

if ( file_exists( $filepath ) ) {

file_put_contents( $filepath, $content );

return response()->json( 'success' );

} else {

throw new FileNotFoundException( 'We can\'t find deploy script defined for this client' );
}

} else {

throw new BadRequestHttpException( 'Parameter content is required.' );
}
}
}
2 changes: 1 addition & 1 deletion src/Http/Controllers/Front/Ajax/ClientsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,6 @@ public function changeAutoDeploy( Client $client )
{
$client->changeAutoDeploy();

return response()->json( 'success' );
return response()->json( compact( $client ) );
}
}
90 changes: 65 additions & 25 deletions src/Http/Controllers/Front/Ajax/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,33 @@

namespace KgBot\LaravelDeploy\Http\Controllers\Front\Ajax;

use Dubture\Monolog\Reader\LogReader;
use KgBot\LaravelDeploy\Http\Controllers\BaseController;
use KgBot\LaravelDeploy\Jobs\DeployJob;
use KgBot\LaravelDeploy\Models\Client;
use KgBot\LaravelDeploy\Utils\LogParser;

class SettingsController extends BaseController
{
protected $lf_characters = [ '\r\n', '\n\r', '\r', '\n' ];

/**
* Return last deploy log
*
* @return \Illuminate\Http\JsonResponse
* @throws \Exception
*/
public function lastLog()
{

$log_file_name = config( 'laravel-deploy.log_file_name', 'laravel-log' );
$path = storage_path( 'logs/' . $log_file_name );

if ( file_exists( $path ) ) {

$reader = new LogReader( $path );
$pattern =
'/\[(?P<date>.*)\] (?P<logger>[\w-\s]+).(?P<level>\w+): (?P<message>[^\[\{]+) (?P<context>[\[\{].*[\]\}]) (?P<extra>[\[\{].*[\]\}])/';
$reader->getParser()->registerPattern( 'newPatternName', $pattern );
$reader->setPattern( 'newPatternName' );
$reader = $this->getLogs();

} else {
if ( is_null( $reader ) ) {

return response()->json( 'Log file path does not exist, check your configuration and try again.', 404 );
}

if ( count( $reader ) ) {

$log = $reader[ count( $reader ) - 2 ];
$log[ 'message' ] = str_replace( $this->lf_characters, '<br />', $log[ 'message' ] );
$log = $reader[ 0 ];

return response()->json( [ 'log' => $log ] );

Expand All @@ -49,25 +39,51 @@ public function lastLog()
}

/**
* Return collection of all logs
* Read deployment log file and return it's content
*
* @return \Illuminate\Http\JsonResponse
* @return array|\KgBot\LaravelDeploy\Utils\LogParser|null
* @throws \Exception
*/
public function allLogs()
protected function getLogs()
{
$log_file_name = config( 'laravel-deploy.log_file_name', 'laravel-log' );
$path = storage_path( 'logs/' . $log_file_name );

if ( file_exists( $path ) ) {

$reader = new LogReader( $path );
$pattern =
'/\[(?P<date>.*)\] (?P<logger>[\w-\s]+).(?P<level>\w+): (?P<message>[^\[\{]+) (?P<context>[\[\{].*[\]\}]) (?P<extra>[\[\{].*[\]\}])/';
$reader->getParser()->registerPattern( 'newPatternName', $pattern );
$reader->setPattern( 'newPatternName' );
$file = file_get_contents( $path );
if ( $file ) {

$reader = new LogParser();
$reader = $reader->parse( $file );

return $reader;

} else {

throw new \Exception( 'Couldn\'t read deployment log file.' );
}


} else {

return null;

}
}

/**
* Return collection of all deploy logs
*
* @return \Illuminate\Http\JsonResponse
* @throws \Exception
*/
public function allLogs()
{
$reader = $this->getLogs();

if ( is_null( $reader ) ) {

return response()->json( 'Log file path does not exist, check your configuration and try again.', 404 );
}

Expand All @@ -81,17 +97,41 @@ public function allLogs()
}
}

/**
* Start deployment from web dashboard
*
* @param \KgBot\LaravelDeploy\Models\Client $client
*
* @return \Illuminate\Http\JsonResponse
*/
public function deployNow( Client $client )
{

dispatch( new DeployJob( $client, base_path( $client->script_source ) ) );
dispatch( new DeployJob( $client,
base_path( $client->script_source ) ) )->onQueue( config( 'laravel-deploy.queue' ) );

return response()->json( 'success' );
}

/**
* Open settings page of web dashboard
*
* @return \Illuminate\Http\JsonResponse
*/
public function index()
{
$clients = Client::Active()->get();
/**
* @var \Illuminate\Support\Collection
*/
$clients = Client::Active()->get();

$clients = $clients->each( function ( $client ) {

$enabled = ( $client->active ) ? 'Enabled' : 'Disabled';

return $client->text = $client->name . ' - ' . $enabled;
} );

$settings = [

'quick_deploy' => config( 'laravel-deploy.run_deploy' ),
Expand Down
82 changes: 50 additions & 32 deletions src/Jobs/DeployJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use KgBot\LaravelDeploy\Events\LaravelDeployFinished;
use KgBot\LaravelDeploy\Events\LaravelDeployStarted;
use KgBot\LaravelDeploy\Models\Client;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Symfony\Component\Process\Process;
Expand All @@ -25,6 +26,21 @@ class DeployJob implements ShouldQueue
public $client;
public $script_file;

/**
* @var Logger
*/
protected $logger;

/**
* @var Process
*/
protected $process;

/**
* @var string $command Command to be executed
*/
protected $command;


/**
* Create a new job instance.
Expand All @@ -35,64 +51,66 @@ public function __construct( Client $client, string $script_file )
{
$this->client = $client;
$this->script_file = $script_file;
$this->setLogger();
$this->setProcess();
}

/**
* Execute the job.
*
* @return void
*/
public function handle()
protected function setLogger()
{
$logger = new Logger( 'laravel-deploy-logger' );
$this->logger = new Logger( 'laravel-deploy-logger' );

$log_file_name = config( 'laravel-deploy.log_file_name', 'laravel-log' );
$stream = new StreamHandler( storage_path( '/logs/' . $log_file_name ), Logger::DEBUG );
$formatter = tap( new LineFormatter( null, null, true, true ), function ( $formatter ) {
$formatter->includeStacktraces();
} );
$stream->setFormatter( $formatter );


$logger->pushHandler( $stream );
$this->logger->pushHandler( $stream );
}

$command = 'echo \'' . config( 'laravel-deploy.user.password' );
$command .= '\' | sudo -S -u ' . config( 'laravel-deploy.user.username' );
protected function setProcess()
{
$command = 'echo ' . config( 'laravel-deploy.user.password' );
$command .= ' | sudo -S -u ' . config( 'laravel-deploy.user.username' );
$command .= ' sh ' . $this->script_file;

$command = 'sh ' . $this->script_file;
echo $command;
$this->command = $command;

$process = new Process( $command );
$process->setTimeout( 300 );
$message = '';
$error = '';
event( new LaravelDeployStarted( $this->client, $command ) );

ini_set( 'max_execution_time', 200 );
$process->run( function ( $type, $buffer ) use ( &$message, &$error ) {
$process->setTimeout( 500 );
$process->setIdleTimeout( 100 );

if ( Process::ERR === $type ) {

$error .= $buffer . '\r\n';
$this->process = $process;
}

} else {
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
event( new LaravelDeployStarted( $this->client, $this->command ) );

$message .= $buffer . '\r\n';
}
} );
$this->process->run();

if ( $message !== '' ) {
if ( $this->process->isSuccessful() ) {

$logger->info( $message, [
$this->logger->info( PHP_EOL . $this->process->getOutput(), [
'client' => json_encode( $this->client ),
'script' => $this->script_file,
] );
event( new LaravelDeployFinished( $this->client, $message ) );
event( new LaravelDeployFinished( $this->client, $this->process->getOutput() ) );

} else if ( $error !== '' ) {
} else {

$logger->critical( $error, [
$this->logger->critical( PHP_EOL . $this->process->getOutput(), [
'client' => json_encode( $this->client ),
'script' => $this->script_file,
] );
event( new LaravelDeployFailed( $this->client, $error ) );
event( new LaravelDeployFailed( $this->client, $this->process->getOutput() ) );
}

}
Expand Down
Loading

0 comments on commit da2697c

Please sign in to comment.