Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] APPS-4380 Add default endpoints to PBC #14

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The following console commands are available:
- `vendor/bin/syncapi schema:openapi:create`
- `vendor/bin/syncapi schema:openapi:validate`
- `vendor/bin/syncapi code:openapi:generate`
- `vendor/bin/syncapi code:openapi:update`

## Adding an OpenAPI file

Expand All @@ -35,9 +36,12 @@ The `vendor/bin/syncapi schema:openapi:create` adds a minimal OpenAPI file.

The `vendor/bin/syncapi schema:openapi:validate` validates an OpenAPI file.


## Create code from an existing OpenAPI

The `vendor/bin/syncapi code:openapi:generate` reads an existing OpenAPI file and creates code out of it.

## Update an OpenApi file with provided OpenApi schema

The `vendor/bin/syncapi code:openapi:update` updates an existing OpenAPI file (or creates a new one if the file doesn't exist) with the provided JSON.


2 changes: 2 additions & 0 deletions bin/syncapi
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ if (!defined('COMPOSER_INSTALL')) {

require_once COMPOSER_INSTALL;

use SprykerSdk\SyncApi\Console\OpenApiUpdateConsole;
use Symfony\Component\Console\Application;
use SprykerSdk\SyncApi\Console\OpenApiCodeGenerateConsole;
use SprykerSdk\SyncApi\Console\OpenApiValidateConsole;
Expand All @@ -27,6 +28,7 @@ $application->addCommands([
new OpenApiCodeGenerateConsole(),
new OpenApiValidateConsole(),
new OpenApiCreateConsole(),
new OpenApiUpdateConsole(),
]);

$application->run();
2 changes: 1 addition & 1 deletion codeception.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ coverage:
include:
- src/SprykerSdk/SyncApi/*
suites:
AsyncApi:
SyncApi:
path: SprykerSdkTest/SyncApi
class_name: SyncApiTester
modules:
Expand Down
11 changes: 11 additions & 0 deletions src/SprykerSdk/SyncApi/Console/AbstractConsole.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ class AbstractConsole extends Command
*/
protected ?SyncApiFacadeInterface $facade = null;

/**
* @param string|null $name
* @param \SprykerSdk\SyncApi\SyncApiConfig|null $syncApiConfig
*/
public function __construct(?string $name = null, ?SyncApiConfig $syncApiConfig = null)
{
$this->config = $syncApiConfig;

parent::__construct($name);
}

/**
* @return \SprykerSdk\SyncApi\SyncApiConfig
*/
Expand Down
111 changes: 111 additions & 0 deletions src/SprykerSdk/SyncApi/Console/OpenApiUpdateConsole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

/**
* Copyright © 2019-present Spryker Systems GmbH. All rights reserved.
* Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
*/

namespace SprykerSdk\SyncApi\Console;

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Transfer\UpdateOpenApiRequestTransfer;

class OpenApiUpdateConsole extends AbstractConsole
{
/**
* @var string
*/
public const ARGUMENT_OPENAPI_DOC = 'openapi-doc';

/**
* @var string
*/
public const ARGUMENT_OPENAPI_DOC_DESCRIPTION = 'A JSON-ed string that contains a valid OpenAPI scheme';

/**
* @var string
*/
public const OPTION_OPEN_API_FILE = 'openapi-file';

/**
* @var string
*/
public const OPTION_OPEN_API_FILE_SHORT = 'f';

/**
* @var string
*/
public const OPTION_OPEN_API_FILE_DESCRIPTION = 'Path to target OpenAPI file. Use this option only when your file is not in the default path or has a different name. Defaults to: resources/api/openapi.json';

/**
* @var string
*/
public const OPTION_PROJECT_ROOT = 'project-root';

/**
* @var string
*/
public const OPTION_PROJECT_ROOT_SHORT = 'r';

/**
* @var string
*/
public const OPTION_PROJECT_ROOT_DESCRIPTION = 'Project root directory. By default project root is retrieved from getcwd() function.';

/**
* @return void
*/
protected function configure(): void
{
$this->setName('schema:openapi:update')
->setDescription('Updates an OpenAPI file specified in options with provided OpenAPI doc')
->addArgument(
static::ARGUMENT_OPENAPI_DOC,
InputArgument::REQUIRED,
static::ARGUMENT_OPENAPI_DOC_DESCRIPTION,
)
->addOption(
static::OPTION_OPEN_API_FILE,
static::OPTION_OPEN_API_FILE_SHORT,
InputOption::VALUE_OPTIONAL,
static::OPTION_OPEN_API_FILE_DESCRIPTION,
$this->getConfig()->getDefaultRelativePathToOpenApiFile(),
)
->addOption(
static::OPTION_PROJECT_ROOT,
static::OPTION_PROJECT_ROOT_SHORT,
InputOption::VALUE_OPTIONAL,
static::OPTION_PROJECT_ROOT_DESCRIPTION,
$this->getConfig()->getProjectRootPath(),
);
}

/**
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return int
*/
public function execute(InputInterface $input, OutputInterface $output): int
{
$updateOpenApiRequestTransfer = (new UpdateOpenApiRequestTransfer())
->setOpenApiDoc($input->getArgument(static::ARGUMENT_OPENAPI_DOC))
->setOpenApiFile($input->getOption(static::OPTION_OPEN_API_FILE))
->setProjectRoot($input->getOption(static::OPTION_PROJECT_ROOT));

$openApiResponseTransfer = $this->getFacade()->updateOpenApi($updateOpenApiRequestTransfer);

if ($openApiResponseTransfer->getErrors()->count() === 0) {
$this->printMessages($output, $openApiResponseTransfer->getMessages());

return static::CODE_SUCCESS;
}

$this->printMessages($output, $openApiResponseTransfer->getErrors());

return static::CODE_ERROR;
}
}
14 changes: 14 additions & 0 deletions src/SprykerSdk/SyncApi/Exception/OpenApiFileReadException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

/**
* Copyright © 2019-present Spryker Systems GmbH. All rights reserved.
* Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
*/

namespace SprykerSdk\SyncApi\Exception;

use RuntimeException;

class OpenApiFileReadException extends RuntimeException
{
}
30 changes: 30 additions & 0 deletions src/SprykerSdk/SyncApi/Message/SyncApiError.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,36 @@ public static function couldNotFindOpenApi(string $path): string
);
}

/**
* @param string $errorMessage
*
* @return string
*/
public static function openApiDataIsInvalid(string $errorMessage): string
{
return static::format(
sprintf(
'Provided Open API data is invalid. Error: %s',
$errorMessage,
),
);
}

/**
* @param string $errorMessage
*
* @return string
*/
public static function couldNotUpdateOpenApiFile(string $errorMessage): string
{
return static::format(
sprintf(
'Update Open API failed with error: "%s"',
$errorMessage,
),
);
}

/**
* Colorize output in CLI on Linux machines.
*
Expand Down
10 changes: 10 additions & 0 deletions src/SprykerSdk/SyncApi/Message/SyncApiInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ public static function openApiFileCreated(string $fileName): string
return static::format(sprintf('Successfully created "%s".', $fileName));
}

/**
* @param string $fileName
*
* @return string
*/
public static function openApiFileUpdated(string $fileName): string
{
return static::format(sprintf('Successfully updated "%s".', $fileName));
}

/**
* Colorize output in CLI on Linux machines.
*
Expand Down
6 changes: 3 additions & 3 deletions src/SprykerSdk/SyncApi/OpenApi/Builder/OpenApiCodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ protected function preparePropertyNameForCommand(array $parameters): array
*
* @return string|null
*/
protected function getTransferPropertyType(array $parameters)
protected function getTransferPropertyType(array $parameters): ?string
{
if (count($parameters) === 1) {
$propertyName = array_key_first($parameters);
Expand All @@ -774,7 +774,7 @@ protected function getTransferPropertyType(array $parameters)
*
* @return string|null
*/
protected function getTransferPropertySingular(array $parameters)
protected function getTransferPropertySingular(array $parameters): ?string
{
$propertyName = array_key_first($parameters);
$propertyTypes = explode(':', $parameters[$propertyName]);
Expand Down Expand Up @@ -856,7 +856,7 @@ protected function runProcess(array $command): void
{
$process = new Process($command, $this->config->getProjectRootPath(), null, null, 300);

$process->run(function ($a, $buffer) {
$process->run(function ($a, $buffer): void {
echo $buffer;
// For debugging purposes, set a breakpoint here to see issues.
});
Expand Down
109 changes: 109 additions & 0 deletions src/SprykerSdk/SyncApi/OpenApi/Merger/ComponentsCleaner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

/**
* Copyright © 2019-present Spryker Systems GmbH. All rights reserved.
* Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
*/

namespace SprykerSdk\SyncApi\OpenApi\Merger;

use cebe\openapi\spec\OpenApi;
use cebe\openapi\Writer;

class ComponentsCleaner implements ComponentsCleanerInterface
{
use OpenApiAccessorTrait;

/**
* @param \cebe\openapi\spec\OpenApi $openApi
*
* @return \cebe\openapi\spec\OpenApi
*/
public function cleanUnused(OpenApi $openApi): OpenApi
{
$openApiAsArray = json_decode(Writer::writeToJson($openApi), true);

$references = ReferenceFinder::findInArray($openApiAsArray);

$openApi = $this->cleanUnusedParameters($openApi, $references);

return $this->cleanUnusedSchemas($openApi, $references);
}

/**
* @param \cebe\openapi\spec\OpenApi $openApi
* @param array<string> $references
*
* @return \cebe\openapi\spec\OpenApi
*/
protected function cleanUnusedParameters(OpenApi $openApi, array $references): OpenApi
{
foreach (array_keys($this->getParameters($openApi)) as $parameterName) {
$paramReferenceName = $this->createParameterReferenceName($parameterName);

if (!in_array($paramReferenceName, $references)) {
$this->getComponents($openApi)->parameters = $this->filterSchemasByKey(
$this->getComponents($openApi)->parameters,
$parameterName,
);
}
}

return $openApi;
}

/**
* @param \cebe\openapi\spec\OpenApi $openApi
* @param array<string> $references
*
* @return \cebe\openapi\spec\OpenApi
*/
protected function cleanUnusedSchemas(OpenApi $openApi, array $references): OpenApi
{
foreach (array_keys($this->getSchemas($openApi)) as $schemaName) {
$schemaReferenceName = $this->createSchemaReferenceName($schemaName);

if (!in_array($schemaReferenceName, $references)) {
$this->getComponents($openApi)->schemas = $this->filterSchemasByKey(
$this->getComponents($openApi)->schemas,
$schemaName,
);
}
}

return $openApi;
}

/**
* @param string $parameterName
*
* @return string
*/
protected function createParameterReferenceName(string $parameterName): string
{
return '#/components/parameters/' . $parameterName;
}

/**
* @param string $schemaName
*
* @return string
*/
protected function createSchemaReferenceName(string $schemaName): string
{
return '#/components/schemas/' . $schemaName;
}

/**
* @param array $schemas
* @param string $schemaName
*
* @return array
*/
protected function filterSchemasByKey(array $schemas, string $schemaName): array
{
unset($schemas[$schemaName]);

return $schemas;
}
}
Loading