Skip to content

Commit

Permalink
feat: merge temp documentation generated by different workers into si…
Browse files Browse the repository at this point in the history
…ngle file for saving to production;
  • Loading branch information
vitgrams committed Nov 28, 2024
1 parent 688fe0b commit e3d84f5
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 18 deletions.
15 changes: 12 additions & 3 deletions src/Contracts/SwaggerDriverContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,26 @@
interface SwaggerDriverContract
{
/**
* Save temporary data
* Save current temporary data
*
* @param array $data
*/
public function saveTmpData($data);
public function saveTmpData(array $data);

/**
* Get temporary data
* Get current temporary data
*/
public function getTmpData();

/**
* Save shared (result) temporary data
*/
public function saveSharedTmpData(callable $callback): void;

/**
* Get shared (result) temporary data
*/
public function getSharedTmpData();
/**
* Save production data
*/
Expand Down
78 changes: 70 additions & 8 deletions src/Drivers/BaseDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,99 @@

namespace RonasIT\AutoDoc\Drivers;

use Illuminate\Support\Facades\ParallelTesting;
use RonasIT\AutoDoc\Contracts\SwaggerDriverContract;
use RuntimeException;

abstract class BaseDriver implements SwaggerDriverContract
{
protected string $tempFilePath;
public readonly string $tempFilePath;
public readonly string $sharedTempFilePath;

public function __construct()
{
$this->tempFilePath = storage_path('temp_documentation.json');
$this->sharedTempFilePath = storage_path('temp_documentation.json');

$this->tempFilePath = ($token = ParallelTesting::token())
? storage_path("temp_documentation_{$token}.json")
: $this->sharedTempFilePath;
}

public function saveTmpData($data): void
public function saveTmpData(array $data): void
{
file_put_contents($this->tempFilePath, json_encode($data));
$this->saveJsonToFile($this->tempFilePath, $data);
}

public function getTmpData(): ?array
{
return $this->getJsonFromFile($this->tempFilePath);
}

public function saveSharedTmpData(callable $callback): void
{
$this->writeFileWithLock(
filePath: $this->sharedTempFilePath,
callback: function () use ($callback) {
$data = $callback();

$this->saveJsonToFile($this->sharedTempFilePath, $data);
},
);
}

public function getSharedTmpData(): ?array
{
return $this->getJsonFromFile($this->sharedTempFilePath);
}

protected function clearTmpData(): void
{
if (file_exists($this->tempFilePath)) {
$content = file_get_contents($this->tempFilePath);
unlink($this->tempFilePath);
}
}

protected function saveJsonToFile(string $filePath, array $data): void
{
file_put_contents($filePath, json_encode($data));
}

protected function getJsonFromFile(string $filePath): ?array
{
if (file_exists($filePath)) {
$content = file_get_contents($filePath);

return json_decode($content, true);
}

return null;
}

protected function clearTmpData(): void
protected function writeFileWithLock(string $filePath, callable $callback, int $maxRetries = 20, int $minWaitTime = 100, int $maxWaitTime = 1000): void
{
if (file_exists($this->tempFilePath)) {
unlink($this->tempFilePath);
$handle = fopen($filePath, 'c+');

if ($handle === false) {
throw new RuntimeException("Unable to open file: {$filePath}");
}

$retryCounter = 0;

try {
while (!flock($handle, LOCK_EX | LOCK_NB)) {
if ($retryCounter >= $maxRetries) {
throw new RuntimeException("Unable to lock file: {$filePath}");
}

usleep(rand($minWaitTime, $maxWaitTime));

$retryCounter++;
}

$callback($handle);
} finally {
flock($handle, LOCK_UN);
fclose($handle);
}
}
}
2 changes: 1 addition & 1 deletion src/Drivers/LocalDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function __construct()

public function saveData(): void
{
file_put_contents($this->prodFilePath, json_encode($this->getTmpData()));
file_put_contents($this->prodFilePath, json_encode($this->getSharedTmpData()));

$this->clearTmpData();
}
Expand Down
2 changes: 1 addition & 1 deletion src/Drivers/RemoteDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function __construct()

public function saveData(): void
{
$this->makeHttpRequest('post', $this->getUrl(), $this->getTmpData(), [
$this->makeHttpRequest('post', $this->getUrl(), $this->getSharedTmpData(), [
'Content-Type: application/json',
]);

Expand Down
2 changes: 1 addition & 1 deletion src/Drivers/StorageDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function __construct()

public function saveData(): void
{
$this->disk->put($this->prodFilePath, json_encode($this->getTmpData()));
$this->disk->put($this->prodFilePath, json_encode($this->getSharedTmpData()));

$this->clearTmpData();
}
Expand Down
24 changes: 22 additions & 2 deletions src/Services/SwaggerService.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use ReflectionClass;
use RonasIT\AutoDoc\Contracts\SwaggerDriverContract;
use RonasIT\AutoDoc\Exceptions\DocFileNotExistsException;
use RonasIT\AutoDoc\Exceptions\EmptyContactEmailException;
use RonasIT\AutoDoc\Exceptions\EmptyDocFileException;
Expand All @@ -17,7 +18,6 @@
use RonasIT\AutoDoc\Exceptions\SwaggerDriverClassNotFoundException;
use RonasIT\AutoDoc\Exceptions\UnsupportedDocumentationViewerException;
use RonasIT\AutoDoc\Exceptions\WrongSecurityConfigException;
use RonasIT\AutoDoc\Contracts\SwaggerDriverContract;
use RonasIT\AutoDoc\Traits\GetDependenciesTrait;
use RonasIT\AutoDoc\Validators\SwaggerSpecValidator;
use Symfony\Component\HttpFoundation\Response;
Expand Down Expand Up @@ -802,6 +802,11 @@ public function saveProductionData()
$this->driver->saveData();
}

public function getDocumentation(): array
{
return $this->driver->getDocumentation();
}

public function getDocFileContent()
{
$documentation = $this->driver->getDocumentation();
Expand Down Expand Up @@ -971,7 +976,7 @@ protected function getOpenAPIFileContent(string $filePath): array
return $fileContent;
}

protected function mergeOpenAPIDocs(array &$documentation, array $additionalDocumentation): void
public function mergeOpenAPIDocs(array &$documentation, array $additionalDocumentation): void
{
$paths = array_keys($additionalDocumentation['paths']);

Expand Down Expand Up @@ -1002,4 +1007,19 @@ protected function mergeOpenAPIDocs(array &$documentation, array $additionalDocu
);
}
}

public function mergeTempDocumentation(): void
{
if ($this->driver->tempFilePath !== $this->driver->sharedTempFilePath) {
$this->driver->saveSharedTmpData(function () {
$resultDocContent = $this->driver->getSharedTmpData() ?? $this->generateEmptyData();

$currentDocContent = $this->driver->getTmpData();

$this->mergeOpenAPIDocs($resultDocContent, $currentDocContent);

return $resultDocContent;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace RonasIT\AutoDoc\Support\PHPUnit\EventSubscribers;

use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Application;
use PHPUnit\Event\Application\Finished;
use PHPUnit\Event\Application\FinishedSubscriber;
use RonasIT\AutoDoc\Services\SwaggerService;
Expand All @@ -13,12 +14,15 @@ public function notify(Finished $event): void
{
$this->createApplication();

app(SwaggerService::class)->saveProductionData();
$swaggerService = app(SwaggerService::class);

$swaggerService->mergeTempDocumentation();
$swaggerService->saveProductionData();
}

protected function createApplication(): void
{
$app = require base_path('bootstrap/app.php');
$app = require Application::inferBasePath() . '/bootstrap/app.php';

$app->loadEnvironmentFrom('.env.testing');
$app->make(Kernel::class)->bootstrap();
Expand Down

0 comments on commit e3d84f5

Please sign in to comment.