From f4798fc87d82221c6178e631d7b6cefa1aa9974d Mon Sep 17 00:00:00 2001 From: bknutson Date: Wed, 15 Jan 2025 12:01:16 -0700 Subject: [PATCH] [SPN-1440] New Guardrail Check to ensure documentation is present and report on deprecated web APIs --- src/Checks/ErrorConstants.php | 1 + src/Checks/WebApiDocumentationCheck.php | 66 +++++++++++++++++++ src/NodeVisitors/StaticAnalyzer.php | 2 + .../TestWebApiDocumentationCheck.1.inc | 29 ++++++++ .../TestWebApiDocumentationCheck.2.inc | 17 +++++ .../TestWebApiDocumentationCheck.3.inc | 18 +++++ .../Checks/TestWebApiDocumentationCheck.php | 29 ++++++++ 7 files changed, 162 insertions(+) create mode 100644 src/Checks/WebApiDocumentationCheck.php create mode 100644 tests/units/Checks/TestData/TestWebApiDocumentationCheck.1.inc create mode 100644 tests/units/Checks/TestData/TestWebApiDocumentationCheck.2.inc create mode 100644 tests/units/Checks/TestData/TestWebApiDocumentationCheck.3.inc create mode 100644 tests/units/Checks/TestWebApiDocumentationCheck.php diff --git a/src/Checks/ErrorConstants.php b/src/Checks/ErrorConstants.php index 9945299..5f387ee 100644 --- a/src/Checks/ErrorConstants.php +++ b/src/Checks/ErrorConstants.php @@ -82,6 +82,7 @@ class ErrorConstants { const TYPE_VARIABLE_FUNCTION_NAME = 'Standard.VariableFunctionCall'; const TYPE_VARIABLE_VARIABLE = 'Standard.VariableVariable'; const TYPE_COUNTABLE_EMPTINESS_CHECK = 'Standard.Countable.Emptiness'; + const TYPE_WEB_API_DOCUMENTATION_CHECK = 'Standard.WebApi.Documentation'; /** diff --git a/src/Checks/WebApiDocumentationCheck.php b/src/Checks/WebApiDocumentationCheck.php new file mode 100644 index 0000000..d62cd21 --- /dev/null +++ b/src/Checks/WebApiDocumentationCheck.php @@ -0,0 +1,66 @@ +isPublic()) { + foreach ($node->attrGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attribute) { + $attributeName = $attribute->name->toString(); + if (str_starts_with($attributeName, 'OpenApi\Attributes')) { + foreach ($attribute->args as $arg) { + if ($arg->name->name === 'deprecated' && $arg->value->name->toString() == 'true') { + $this->metricOutput->emitMetric(new Metric( + $fileName, + $node->getLine(), + ErrorConstants::TYPE_METRICS_DEPRECATED_FUNCTIONS, + [] + )); + break; + } + } + + return; + } + } + } + + $className = $inside->namespacedName->toString(); + $this->emitErrorOnLine( + $fileName, + $node->getLine(), + ErrorConstants::TYPE_WEB_API_DOCUMENTATION_CHECK, + "All public controller methods should be associated with a route and must have + documentation through an OpenAPI Attribute. Method: {$node->name->name}, Class: $className" + ); + } + } +} \ No newline at end of file diff --git a/src/NodeVisitors/StaticAnalyzer.php b/src/NodeVisitors/StaticAnalyzer.php index 0035542..1c04ff2 100644 --- a/src/NodeVisitors/StaticAnalyzer.php +++ b/src/NodeVisitors/StaticAnalyzer.php @@ -43,6 +43,7 @@ use BambooHR\Guardrail\Checks\UnsafeSuperGlobalCheck; use BambooHR\Guardrail\Checks\UnusedPrivateMemberVariableCheck; use BambooHR\Guardrail\Checks\UseStatementCaseCheck; +use BambooHR\Guardrail\Checks\WebApiDocumentationCheck; use BambooHR\Guardrail\Config; use BambooHR\Guardrail\Evaluators as Ev; use BambooHR\Guardrail\Evaluators\ExpressionInterface; @@ -157,6 +158,7 @@ function __construct(SymbolTable $index, OutputInterface $output, MetricOutputIn new ThrowsCheck($this->index, $output), new CountableEmptinessCheck($this->index, $output), new DependenciesOnVendorCheck($this->index, $output, $metricOutput), + new WebApiDocumentationCheck($this->index, $output, $metricOutput), //new ClassStoredAsVariableCheck($this->index, $output) ]; diff --git a/tests/units/Checks/TestData/TestWebApiDocumentationCheck.1.inc b/tests/units/Checks/TestData/TestWebApiDocumentationCheck.1.inc new file mode 100644 index 0000000..346ef3a --- /dev/null +++ b/tests/units/Checks/TestData/TestWebApiDocumentationCheck.1.inc @@ -0,0 +1,29 @@ +assertEquals(2, $this->runAnalyzerOnFile('.1.inc', ErrorConstants::TYPE_WEB_API_DOCUMENTATION_CHECK,), ""); + } + + /** + * @return void + */ + public function testOnlyErrorsOnPublicMethods() { + $this->assertEquals(2, $this->runAnalyzerOnFile('.2.inc', ErrorConstants::TYPE_WEB_API_DOCUMENTATION_CHECK,), ""); + } + + public function testMethodWithDeprecatedAttribute() { + $output = $this->getOutputFromAnalyzer('.3.inc', ErrorConstants::TYPE_METRICS_DEPRECATED_FUNCTIONS); + $this->assertEquals(1, $this->getMetricCountByName($output, ErrorConstants::TYPE_METRICS_DEPRECATED_FUNCTIONS)); + } +} \ No newline at end of file