Changes output to JSON serialization.

This commit is contained in:
Joao Patricio 2023-04-07 15:58:45 +01:00
parent 2a8d603f98
commit e6f0059e5e
10 changed files with 62 additions and 130 deletions

View File

@ -20,12 +20,12 @@ public function __construct(RemoteProcessArgs $remoteProcessArgs)
->withProperties($properties) ->withProperties($properties)
->performedOn($remoteProcessArgs->model) ->performedOn($remoteProcessArgs->model)
->event($remoteProcessArgs->type) ->event($remoteProcessArgs->type)
->log(""); ->log("[]");
} else { } else {
$this->activity = activity() $this->activity = activity()
->withProperties($remoteProcessArgs->toArray()) ->withProperties($remoteProcessArgs->toArray())
->event($remoteProcessArgs->type) ->event($remoteProcessArgs->type)
->log(""); ->log("[]");
} }
} }

View File

@ -27,11 +27,6 @@ class RunRemoteProcess
protected int $counter = 1; protected int $counter = 1;
public const MARK_START = "|--";
public const MARK_END = "--|";
public const SEPARATOR = '|';
public const MARK_REGEX = "/(\|--\d+\|\d+\|(?:out|err)--\|)/";
/** /**
* Create a new job instance. * Create a new job instance.
*/ */
@ -93,7 +88,7 @@ protected function handleOutput(string $type, string $output)
$this->currentTime = $this->elapsedTime(); $this->currentTime = $this->elapsedTime();
$this->activity->description .= $this->encodeOutput($type, $output); $this->activity->description = $this->encodeOutput($type, $output);
if ($this->isAfterLastThrottle()) { if ($this->isAfterLastThrottle()) {
// Let's write to database. // Let's write to database.
@ -106,12 +101,37 @@ protected function handleOutput(string $type, string $output)
public function encodeOutput($type, $output) public function encodeOutput($type, $output)
{ {
return $outputStack = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
static::MARK_START . $this->counter++ .
static::SEPARATOR . $this->elapsedTime() . $outputStack[] = [
static::SEPARATOR . $type . 'type' => $type,
static::MARK_END . 'output' => $output,
$output; 'elapsed_tim' => $this->elapsedTime(),
'order' => $this->counter++,
];
return json_encode($outputStack, flags: JSON_THROW_ON_ERROR);
}
public static function decodeOutput(?Activity $activity = null): string
{
if(is_null($activity)) {
return '';
}
try {
$decoded = json_decode(data_get($activity, 'description'),
associative: true,
flags: JSON_THROW_ON_ERROR
);
} catch (\JsonException $exception) {
return '';
}
return collect($decoded)
->sortBy(fn($i) => $i['order'])
->map(fn($i) => $i['output'])
->implode("\n");
} }
/** /**

View File

@ -1,90 +0,0 @@
<?php
namespace App\Actions\RemoteProcess;
use Illuminate\Support\Collection;
use Spatie\Activitylog\Models\Activity;
class TidyOutput
{
protected $output;
public function __construct(
protected Activity $activity
)
{
}
public function __invoke()
{
$chunks = preg_split(
RunRemoteProcess::MARK_REGEX,
$this->activity->description,
flags: PREG_SPLIT_DELIM_CAPTURE
);
$tidyRows = $this
->joinMarksWithFollowingItem($chunks)
->reject(fn($i) => $i === '')
->map(function ($i) {
if (!preg_match('/\|--(\d+)\|(\d+)\|(out|err)--\|(.*)/', $i, $matches)) {
return $i;
}
[$wholeLine, $sequence, $elapsedTime, $type, $output] = $matches;
return [
'sequence' => $sequence,
'time' => $elapsedTime,
'type' => $type,
'output' => $output,
];
});
return $tidyRows
->sortBy(fn($i) => $i['sequence'])
->map(fn($i) => $i['output'])
->implode("\n");
}
/**
* Function to join the defined mark, with the output
* that is the following element in the array.
*
* Turns this:
* [
* "|--1|149|out--|",
* "/root\n",
* "|--2|251|out--|",
* "Welcome 1 times 1\n",
* "|--3|366|out--|",
* "Welcome 2 times 2\n",
* "|--4|466|out--|",
* "Welcome 3 times 3\n",
* ]
*
* into this:
*
* [
* "|--1|149|out--|/root\n",
* "|--2|251|out--|Welcome 1 times 1\n",
* "|--3|366|out--|Welcome 2 times 2\n",
* "|--4|466|out--|Welcome 3 times 3\n",
* ]
*/
public function joinMarksWithFollowingItem($chunks): Collection
{
return collect($chunks)->reduce(function ($carry, $item) {
$last = $carry->last();
if (preg_match(RunRemoteProcess::MARK_REGEX, $last) && !preg_match(RunRemoteProcess::MARK_REGEX, $item)) {
// If the last element is a delimiter and the current element is not,
// join them together and replace the last element with the joined string
$carry->pop();
$joined = $last . $item;
$carry->push($joined);
} else {
// Otherwise, just add the current element to the result array
$carry->push($item);
}
return $carry;
}, collect());
}
}

View File

@ -2,21 +2,10 @@
namespace App\Http\Livewire; namespace App\Http\Livewire;
use App\Jobs\ContainerStatusJob;
use App\Jobs\DeployApplicationJob; use App\Jobs\DeployApplicationJob;
use App\Models\Application; use App\Models\Application;
use App\Models\CoolifyInstanceSettings;
use DateTimeImmutable;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Process;
use Livewire\Component; use Livewire\Component;
use Symfony\Component\Yaml\Yaml;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
use Lcobucci\JWT\Encoding\ChainedFormatter;
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Signer\Rsa\Sha256;
use Lcobucci\JWT\Token\Builder;
class DeployApplication extends Component class DeployApplication extends Component
{ {

View File

@ -24,6 +24,7 @@ public function polling()
$this->isKeepAliveOn = false; $this->isKeepAliveOn = false;
} }
} }
public function render() public function render()
{ {
return view('livewire.poll-activity'); return view('livewire.poll-activity');

View File

@ -64,7 +64,7 @@ public function __construct(
->performedOn($this->application) ->performedOn($this->application)
->withProperties($remoteProcessArgs->toArray()) ->withProperties($remoteProcessArgs->toArray())
->event(ActivityTypes::DEPLOYMENT->value) ->event(ActivityTypes::DEPLOYMENT->value)
->log(""); ->log("[]");
} }
/** /**
@ -139,7 +139,7 @@ public function handle(): void
], setStatus: true); ], setStatus: true);
$this->executeNow([ $this->executeNow([
"docker stop -t 0 {$this->deployment_uuid} >/dev/null" "docker stop -t 0 {$this->deployment_uuid} >/dev/null"
]); ], setStatus: true);
} }
private function execute_in_builder(string $command) private function execute_in_builder(string $command)

View File

@ -1,3 +1,5 @@
<div> <div>
<pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn) wire:poll.750ms="polling" @endif>{{ data_get($activity, 'description') }}</pre> <pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn) wire:poll.3750ms="polling" @endif>
{{ \App\Actions\RemoteProcess\RunRemoteProcess::decodeOutput($activity) }}
</pre>
</div> </div>

View File

@ -15,5 +15,18 @@
*/ */
Artisan::command('inspire', function () { Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
$activity = Spatie\Activitylog\Models\Activity::latest()->first();
$this->info(
collect(
json_decode(data_get($activity, 'description'), associative: true, flags: JSON_THROW_ON_ERROR)
)
->sortBy('order')
->map(fn($i) => $i['output'])
->implode("\n")
);
})->purpose('Display an inspiring quote'); })->purpose('Display an inspiring quote');

View File

@ -1,5 +1,6 @@
<?php <?php
use App\Actions\RemoteProcess\RunRemoteProcess;
use App\Actions\RemoteProcess\TidyOutput; use App\Actions\RemoteProcess\TidyOutput;
use App\Models\User; use App\Models\User;
use App\Models\Server; use App\Models\Server;
@ -38,7 +39,7 @@
// Assert there's no containers start with coolify_test_* // Assert there's no containers start with coolify_test_*
$activity = remoteProcess([$areThereCoolifyTestContainers], $host); $activity = remoteProcess([$areThereCoolifyTestContainers], $host);
$tidyOutput = (new TidyOutput($activity))(); $tidyOutput = RunRemoteProcess::decodeOutput($activity);
$containers = formatDockerCmdOutputToJson($tidyOutput); $containers = formatDockerCmdOutputToJson($tidyOutput);
expect($containers)->toBeEmpty(); expect($containers)->toBeEmpty();
@ -48,7 +49,7 @@
// docker ps name = $container // docker ps name = $container
$activity = remoteProcess([$areThereCoolifyTestContainers], $host); $activity = remoteProcess([$areThereCoolifyTestContainers], $host);
$tidyOutput = (new TidyOutput($activity))(); $tidyOutput = RunRemoteProcess::decodeOutput($activity);
$containers = formatDockerCmdOutputToJson($tidyOutput); $containers = formatDockerCmdOutputToJson($tidyOutput);
expect($containers->where('Names', $containerName)->count())->toBe(1); expect($containers->where('Names', $containerName)->count())->toBe(1);

View File

@ -1,7 +1,6 @@
<?php <?php
use App\Actions\RemoteProcess\RunRemoteProcess; use App\Actions\RemoteProcess\RunRemoteProcess;
use App\Actions\RemoteProcess\TidyOutput;
use App\Models\Server; use App\Models\Server;
use Database\Seeders\DatabaseSeeder; use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseMigrations;
@ -24,13 +23,10 @@
], $host); ], $host);
preg_match(RunRemoteProcess::MARK_REGEX, $activity->description, $matchesInRawContent); $tidyOutput = RunRemoteProcess::decodeOutput($activity);
$out = (new TidyOutput($activity))();
preg_match(RunRemoteProcess::MARK_REGEX, $out, $matchesInTidyOutput);
expect($matchesInRawContent)
->not()->toBeEmpty()
->and($matchesInTidyOutput)
->toBeEmpty();
expect($tidyOutput)
->toContain('Welcome 1 times')
->toContain('Welcome 3 times')
->not()->toBeJson();
}); });