Skip to content

Commit

Permalink
Allow config and temp directories to be configured independently.
Browse files Browse the repository at this point in the history
  • Loading branch information
ArclightHub committed Nov 27, 2023
1 parent 26a70c2 commit b653141
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 72 deletions.
9 changes: 5 additions & 4 deletions camel/Camel.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Knuckles\Camel\Output\OutputEndpointData;
use Knuckles\Scribe\Configuration\PathConfig;
use Knuckles\Scribe\Tools\Utils;
use Symfony\Component\Yaml\Yaml;


class Camel
{
public static function cacheDir(string $docsName = 'scribe'): string
public static function cacheDir(PathConfig $pathConfiguration): string
{
return ".$docsName/endpoints.cache";
return $pathConfiguration->getTemporaryDirectoryPath() . "/endpoints.cache";
}

public static function camelDir(string $docsName = 'scribe'): string
public static function camelDir(PathConfig $pathConfiguration): string
{
return ".$docsName/endpoints";
return $pathConfiguration->getTemporaryDirectoryPath() . "/endpoints";
}

/**
Expand Down
1 change: 1 addition & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
<file>tests/Unit/ExtractorTest.php</file>
<file>tests/Unit/ExtractorPluginSystemTest.php</file>
<file>tests/Unit/ConfigDifferTest.php</file>
<file>tests/Unit/PathConfigurationTest.php</file>
</testsuite>
<testsuite name="Unit Tests 2">
<file>tests/Unit/ExtractedEndpointDataTest.php</file>
Expand Down
30 changes: 19 additions & 11 deletions src/Commands/GenerateDocumentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;
use Knuckles\Camel\Camel;
use Knuckles\Scribe\Configuration\PathConfig;
use Knuckles\Scribe\GroupedEndpoints\GroupedEndpointsFactory;
use Knuckles\Scribe\Matching\RouteMatcherInterface;
use Knuckles\Scribe\Tools\ConsoleOutputUtils as c;
Expand All @@ -24,6 +25,7 @@ class GenerateDocumentation extends Command
{--no-extraction : Skip extraction of route and API info and just transform the YAML and Markdown files into HTML}
{--no-upgrade-check : Skip checking for config file upgrades. Won't make things faster, but can be helpful if the command is buggy}
{--config=scribe : choose which config file to use}
{--cache-directory= : choose which cache directory to use}
";

protected $description = 'Generate API documentation from your Laravel/Dingo routes.';
Expand All @@ -34,7 +36,8 @@ class GenerateDocumentation extends Command

protected bool $forcing;

protected string $configName;
/** @var PathConfig */
protected PathConfig $pathConfiguration;

public function handle(RouteMatcherInterface $routeMatcher, GroupedEndpointsFactory $groupedEndpointsFactory): void
{
Expand All @@ -47,9 +50,9 @@ public function handle(RouteMatcherInterface $routeMatcher, GroupedEndpointsFact
}

// Extraction stage - extract endpoint info either from app or existing Camel files (previously extracted data)
$groupedEndpointsInstance = $groupedEndpointsFactory->make($this, $routeMatcher, $this->configName);
$groupedEndpointsInstance = $groupedEndpointsFactory->make($this, $routeMatcher, $this->pathConfiguration);
$extractedEndpoints = $groupedEndpointsInstance->get();
$userDefinedEndpoints = Camel::loadUserDefinedEndpoints(Camel::camelDir($this->configName));
$userDefinedEndpoints = Camel::loadUserDefinedEndpoints(Camel::camelDir($this->pathConfiguration));
$groupedEndpoints = $this->mergeUserDefinedEndpoints($extractedEndpoints, $userDefinedEndpoints);

// Output stage
Expand All @@ -61,7 +64,7 @@ public function handle(RouteMatcherInterface $routeMatcher, GroupedEndpointsFact
$this->writeExampleCustomEndpoint();
}

$writer = new Writer($this->docConfig, $this->configName);
$writer = new Writer($this->docConfig, $this->pathConfiguration);
$writer->writeDocs($groupedEndpoints);

$this->upgradeConfigFileIfNeeded();
Expand Down Expand Up @@ -98,12 +101,17 @@ public function bootstrap(): void

c::bootstrapOutput($this->output);

$this->configName = $this->option('config');
if (!config($this->configName)) {
throw new \InvalidArgumentException("The specified config (config/{$this->configName}.php) doesn't exist.");
$configName = $this->option('config');
if (!config($configName)) {
throw new \InvalidArgumentException("The specified config (config/{$configName}.php) doesn't exist.");
}

$this->docConfig = new DocumentationConfig(config($this->configName));
$this->pathConfiguration = new PathConfig($configName, $configName, true);
if ($this->hasOption('cache-directory') && !empty($this->option('cache-directory'))) {
$this->pathConfiguration = new PathConfig($this->option('cache-directory'), $configName, false);
}

$this->docConfig = new DocumentationConfig(config($this->pathConfiguration->getScribeConfigurationPath()));

// Force root URL so it works in Postman collection
$baseUrl = $this->docConfig->get('base_url') ?? config('app.url');
Expand Down Expand Up @@ -146,7 +154,7 @@ protected function mergeUserDefinedEndpoints(array $groupedEndpoints, array $use
protected function writeExampleCustomEndpoint(): void
{
// We add an example to guide users in case they need to add a custom endpoint.
copy(__DIR__ . '/../../resources/example_custom_endpoint.yaml', Camel::camelDir($this->configName) . '/custom.0.yaml');
copy(__DIR__ . '/../../resources/example_custom_endpoint.yaml', Camel::camelDir($this->pathConfiguration) . '/custom.0.yaml');
}

protected function upgradeConfigFileIfNeeded(): void
Expand All @@ -155,12 +163,12 @@ protected function upgradeConfigFileIfNeeded(): void

$this->info("Checking for any pending upgrades to your config file...");
try {
if (! $this->laravel['files']->exists($this->laravel->configPath("{$this->configName}.php"))) {
if (! $this->laravel['files']->exists($this->laravel->configPath($this->pathConfiguration->getScribeConfigurationPath('php', '.')))) {
$this->info("No config file to upgrade.");
return;
}

$upgrader = Upgrader::ofConfigFile("config/{$this->configName}.php", __DIR__ . '/../../config/scribe.php')
$upgrader = Upgrader::ofConfigFile("config/" . $this->pathConfiguration->getScribeConfigurationPath('php', '.'), __DIR__ . '/../../config/scribe.php')
->dontTouch(
'routes', 'example_languages', 'database_connections_to_transact', 'strategies', 'laravel.middleware',
'postman.overrides', 'openapi.overrides', 'groups', 'examples.models_source'
Expand Down
56 changes: 56 additions & 0 deletions src/Configuration/PathConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Knuckles\Scribe\Configuration;

/**
* A home for path configurations.
*/
class PathConfig
{
/** @var string */
private string $scribeConfig;

/** @var string */
private string $cacheDir;

/** @var bool */
private bool $isHidden;

/**
* @param string $cacheDir
* @param string $scribeConfig
* @param bool $isHidden
*/
public function __construct(string $cacheDir, string$scribeConfig, bool $isHidden = true)
{
$this->cacheDir = $cacheDir;
$this->scribeConfig = $scribeConfig;
$this->isHidden = $isHidden;
}

/**
* @return string
*/
public function getScribeConfigurationPath(string $resolvePath = null, string $separator = '/'): string
{
if (is_null($resolvePath)) {
return $this->scribeConfig;
}
// Separate the path with a /
return sprintf("%s%s%s", $this->scribeConfig, $separator, $resolvePath);
}

/**
* @return string
*/
public function getTemporaryDirectoryPath(string $resolvePath = null): string
{
$path = ($this->isHidden ? '.' : '') . $this->cacheDir;
if (is_null($resolvePath)) {
return $path;
}
// Separate the path with a /
return sprintf("%s/%s", $path, $resolvePath);

}
}
17 changes: 13 additions & 4 deletions src/Extracting/ApiDetails.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Knuckles\Scribe\Extracting;

use Knuckles\Scribe\Configuration\PathConfig;
use Knuckles\Scribe\Tools\ConsoleOutputUtils as c;
use Knuckles\Scribe\Tools\Utils as u;
use Knuckles\Scribe\Tools\DocumentationConfig;
Expand All @@ -23,11 +24,19 @@ class ApiDetails

private array $lastKnownFileContentHashes = [];

public function __construct(DocumentationConfig $config = null, bool $preserveUserChanges = true, string $docsName = 'scribe')
{
$this->markdownOutputPath = ".{$docsName}"; //.scribe by default
/**
* @param PathConfig $pathConfig
* @param DocumentationConfig|null $config
* @param bool $preserveUserChanges
*/
public function __construct(
PathConfig $pathConfig,
DocumentationConfig $config = null,
bool $preserveUserChanges = true
) {
$this->markdownOutputPath = $pathConfig->getTemporaryDirectoryPath(); //.scribe by default
// If no config is injected, pull from global. Makes testing easier.
$this->config = $config ?: new DocumentationConfig(config($docsName));
$this->config = $config ?: new DocumentationConfig(config($pathConfig));
$this->baseUrl = $this->config->get('base_url') ?? config('app.url');
$this->preserveUserChanges = $preserveUserChanges;

Expand Down
39 changes: 30 additions & 9 deletions src/GroupedEndpoints/GroupedEndpointsFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,55 @@
namespace Knuckles\Scribe\GroupedEndpoints;

use Knuckles\Scribe\Commands\GenerateDocumentation;
use Knuckles\Scribe\Configuration\PathConfig;
use Knuckles\Scribe\Matching\RouteMatcherInterface;

class GroupedEndpointsFactory
{
public function make(GenerateDocumentation $command, RouteMatcherInterface $routeMatcher, string $docsName = 'scribe'): GroupedEndpointsContract
{
/**
* @param GenerateDocumentation $command
* @param RouteMatcherInterface $routeMatcher
* @param PathConfig $pathConfig
* @return GroupedEndpointsContract
*/
public function make(
GenerateDocumentation $command,
RouteMatcherInterface $routeMatcher,
PathConfig $pathConfig
): GroupedEndpointsContract {
if ($command->isForcing()) {
return static::fromApp($command, $routeMatcher, false, $docsName);
return static::fromApp($command, $routeMatcher, false, $pathConfig);
}

if ($command->shouldExtract()) {
return static::fromApp($command, $routeMatcher, true, $docsName);
return static::fromApp($command, $routeMatcher, true, $pathConfig);
}

return static::fromCamelDir($docsName);
return static::fromCamelDir($pathConfig);
}

/**
* @param GenerateDocumentation $command
* @param RouteMatcherInterface $routeMatcher
* @param bool $preserveUserChanges
* @param PathConfig $pathConfig
* @return GroupedEndpointsFromApp
*/
public static function fromApp(
GenerateDocumentation $command,
RouteMatcherInterface $routeMatcher,
bool $preserveUserChanges,
string $docsName = 'scribe'
PathConfig $pathConfig
): GroupedEndpointsFromApp {
return new GroupedEndpointsFromApp($command, $routeMatcher, $preserveUserChanges, $docsName);
return new GroupedEndpointsFromApp($command, $routeMatcher, $pathConfig, $preserveUserChanges);
}

public static function fromCamelDir(string $docsName = 'scribe'): GroupedEndpointsFromCamelDir
/**
* @param PathConfig $pathConfig
* @return GroupedEndpointsFromCamelDir
*/
public static function fromCamelDir(PathConfig $pathConfig): GroupedEndpointsFromCamelDir
{
return new GroupedEndpointsFromCamelDir($docsName);
return new GroupedEndpointsFromCamelDir($pathConfig);
}
}
22 changes: 15 additions & 7 deletions src/GroupedEndpoints/GroupedEndpointsFromApp.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Knuckles\Camel\Extraction\ExtractedEndpointData;
use Knuckles\Camel\Output\OutputEndpointData;
use Knuckles\Scribe\Commands\GenerateDocumentation;
use Knuckles\Scribe\Configuration\PathConfig;
use Knuckles\Scribe\Exceptions\CouldntGetRouteDetails;
use Knuckles\Scribe\Extracting\ApiDetails;
use Knuckles\Scribe\Extracting\Extractor;
Expand All @@ -33,15 +34,22 @@ class GroupedEndpointsFromApp implements GroupedEndpointsContract
public static string $camelDir;
public static string $cacheDir;

/**
* @param GenerateDocumentation $command
* @param RouteMatcherInterface $routeMatcher
* @param PathConfig $pathConfiguration
* @param bool $preserveUserChanges
*/
public function __construct(
private GenerateDocumentation $command, private RouteMatcherInterface $routeMatcher,
private bool $preserveUserChanges = true, protected string $docsName = 'scribe'
)
{
private GenerateDocumentation $command,
private RouteMatcherInterface $routeMatcher,
protected PathConfig $pathConfiguration,
private bool $preserveUserChanges = true
) {
$this->docConfig = $command->getDocConfig();

static::$camelDir = Camel::camelDir($this->docsName);
static::$cacheDir = Camel::cacheDir($this->docsName);
static::$camelDir = Camel::camelDir($this->pathConfiguration);
static::$cacheDir = Camel::cacheDir($this->pathConfiguration);
}

public function get(): array
Expand Down Expand Up @@ -282,7 +290,7 @@ protected function extractAndWriteApiDetailsToDisk(): void

protected function makeApiDetails(): ApiDetails
{
return new ApiDetails($this->docConfig, !$this->command->option('force'), $this->docsName);
return new ApiDetails($this->pathConfiguration, $this->docConfig, !$this->command->option('force'));
}

/**
Expand Down
13 changes: 7 additions & 6 deletions src/GroupedEndpoints/GroupedEndpointsFromCamelDir.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@
namespace Knuckles\Scribe\GroupedEndpoints;

use Knuckles\Camel\Camel;
use Knuckles\Scribe\Configuration\PathConfig;

class GroupedEndpointsFromCamelDir implements GroupedEndpointsContract
{
protected string $docsName;
protected PathConfig $pathConfig;

public function __construct(string $docsName = 'scribe')
public function __construct(PathConfig $pathConfig)
{
$this->docsName = $docsName;
$this->pathConfig = $pathConfig;
}

public function get(): array
{
if (!is_dir(Camel::camelDir($this->docsName))) {
if (!is_dir(Camel::camelDir($this->pathConfig))) {
throw new \InvalidArgumentException(
"Can't use --no-extraction because there are no endpoints in the " . Camel::camelDir($this->docsName) . " directory."
"Can't use --no-extraction because there are no endpoints in the " . Camel::camelDir($this->pathConfig) . " directory."
);
}

return Camel::loadEndpointsIntoGroups(Camel::camelDir($this->docsName));
return Camel::loadEndpointsIntoGroups(Camel::camelDir($this->pathConfig));
}

public function hasEncounteredErrors(): bool
Expand Down
Loading

0 comments on commit b653141

Please sign in to comment.