Skip to content

Commit e4eeb72

Browse files
authored
Merge pull request #91 from jmgoncalves97/add-continue-on-errors-option
added continue-on-errors option for use in specific cases such as end…
2 parents 5d64a01 + bc66450 commit e4eeb72

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ The following usage will generate routes with the basic auth specified.
5454
php artisan export:postman --basic="username:password123"
5555
```
5656

57+
The following usage will continue until the end, even if it has error or incompatible endpoints.
58+
59+
```bash
60+
php artisan export:postman --continue-on-errors
61+
```
62+
5763
If both auths are specified, bearer will be favored.
5864

5965
## Examples

phpunit.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
2+
<phpunit
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
bootstrap="vendor/autoload.php"
5+
backupGlobals="false"
6+
colors="true"
7+
processIsolation="false"
8+
stopOnFailure="false"
9+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd"
10+
cacheDirectory=".phpunit.cache"
11+
backupStaticProperties="false"
12+
>
313
<coverage/>
414
<testsuites>
515
<testsuite name="Unit">

src/Commands/ExportPostmanCommand.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Illuminate\Contracts\Validation\ValidationRule;
1010
use Illuminate\Foundation\Http\FormRequest;
1111
use Illuminate\Routing\Router;
12+
use Illuminate\Support\Facades\Log;
1213
use Illuminate\Support\Facades\Storage;
1314
use Illuminate\Support\Facades\Validator;
1415
use Illuminate\Support\Str;
@@ -27,7 +28,8 @@ class ExportPostmanCommand extends Command
2728
/** @var string */
2829
protected $signature = 'export:postman
2930
{--bearer= : The bearer token to use on your endpoints}
30-
{--basic= : The basic auth to use on your endpoints}';
31+
{--basic= : The basic auth to use on your endpoints}
32+
{--continue-on-errors : Continues even if an error occurs in any route, middleware or method (boolean)}';
3133

3234
/** @var string */
3335
protected $description = 'Automatically generate a Postman collection for your API routes';
@@ -62,6 +64,9 @@ class ExportPostmanCommand extends Command
6264
'basic',
6365
];
6466

67+
/** @var bool */
68+
private $stopOnErrors = true;
69+
6570
/** @var \Illuminate\Validation\Validator */
6671
private $validator;
6772

@@ -77,12 +82,14 @@ public function handle(): void
7782
{
7883
$this->setFilename();
7984
$this->setAuthToken();
85+
$this->setOptions();
8086
$this->initializeStructure();
8187
$this->initializePhpDocParser();
8288

8389
foreach ($this->router->getRoutes() as $route) {
8490
$methods = array_filter($route->methods(), fn ($value) => $value !== 'HEAD');
85-
$middlewares = $route->gatherMiddleware();
91+
92+
$middlewares = $this->handleCallable(fn () => $route->gatherMiddleware());
8693

8794
foreach ($methods as $method) {
8895
$includedMiddleware = false;
@@ -103,7 +110,7 @@ public function handle(): void
103110

104111
$routeAction = $route->getAction();
105112

106-
$reflectionMethod = $this->getReflectionMethod($routeAction);
113+
$reflectionMethod = $this->handleCallable(fn () => $this->getReflectionMethod($routeAction));
107114

108115
if (! $reflectionMethod) {
109116
continue;
@@ -223,6 +230,18 @@ public function handle(): void
223230
$this->info('Postman Collection Exported: '.storage_path('app/'.$exportName));
224231
}
225232

233+
protected function handleCallable($callable)
234+
{
235+
try {
236+
return $callable();
237+
} catch (\Throwable $th) {
238+
if ($this->stopOnErrors) {
239+
throw $th;
240+
}
241+
Log::error($th->getMessage()."\n[stacktrace]\n".$th->getTraceAsString()."\n");
242+
}
243+
}
244+
226245
protected function getReflectionMethod(array $routeAction): ?object
227246
{
228247
// Hydrates the closure if it is an instance of Opis\Closure\SerializableClosure
@@ -489,6 +508,13 @@ protected function setAuthToken()
489508
}
490509
}
491510

511+
protected function setOptions()
512+
{
513+
if ($this->option('continue-on-errors') === true) {
514+
$this->stopOnErrors = false;
515+
}
516+
}
517+
492518
protected function isStructured()
493519
{
494520
return $this->config['structured'];

tests/Feature/ExportPostmanTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,32 @@ public function test_basic_export_works(bool $formDataEnabled)
119119
}
120120
}
121121

122+
public function test_continue_on_errors_works()
123+
{
124+
$router = $this->app['router'];
125+
126+
$router->middleware('api')->group(function ($router) {
127+
$router->get('endpoint/with/error', [NonExistentController::class, 'index']);
128+
$router->get('endpoint/without/error', function () {
129+
return 'index';
130+
});
131+
});
132+
133+
$this->artisan('export:postman --continue-on-errors')->assertExitCode(0);
134+
135+
$collection = json_decode(Storage::get('postman/'.config('api-postman.filename')), true);
136+
137+
$collectionRoute = Arr::first($collection['item'], function ($item) {
138+
return $item['name'] == 'endpoint/without/error';
139+
});
140+
$this->assertNotNull($collectionRoute);
141+
142+
$collectionRoute = Arr::first($collection['item'], function ($item) {
143+
return $item['name'] == 'endpoint/with/error';
144+
});
145+
$this->assertNull($collectionRoute);
146+
}
147+
122148
/**
123149
* @dataProvider providerFormDataEnabled
124150
*/

0 commit comments

Comments
 (0)