Skip to content

Commit a644eac

Browse files
Merge pull request #196 from nextcloud/feat/generate-spec/disallow-unused-schemas
feat(generate-spec): Disallow unused schemas
2 parents 40302d1 + 86dfdc3 commit a644eac

File tree

8 files changed

+253
-8
lines changed

8 files changed

+253
-8
lines changed

generate-spec.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,8 @@
940940
}
941941
}
942942

943+
$usedSchemas = ['Capabilities', 'PublicCapabilities'];
944+
943945
foreach ($scopePaths as $scope => $paths) {
944946
$openapiScope = $openapi;
945947

@@ -955,29 +957,29 @@
955957
$openapiScope['paths'] = array_merge(...$fullScopePathArrays);
956958
$openapiScope['components']['schemas'] = $schemas;
957959
} else {
958-
$usedSchemas = [];
960+
$usedRefs = [];
959961
foreach ($paths as $urlRoutes) {
960962
foreach ($urlRoutes as $routeData) {
961963
foreach ($routeData['responses'] as $responseData) {
962964
if (isset($responseData['content']) && $responseData['content'] !== []) {
963-
$usedSchemas[] = Helpers::collectUsedRefs($responseData['content']);
965+
$usedRefs[] = Helpers::collectUsedRefs($responseData['content']);
964966
}
965967
}
966968
if (isset($routeData['requestBody']['content']) && $routeData['requestBody']['content'] !== []) {
967-
$usedSchemas[] = Helpers::collectUsedRefs($routeData['requestBody']['content']);
969+
$usedRefs[] = Helpers::collectUsedRefs($routeData['requestBody']['content']);
968970
}
969971
}
970972
}
971973

972-
$usedSchemas = array_merge(...$usedSchemas);
974+
$usedRefs = array_merge(...$usedRefs);
973975

974976
$scopedSchemas = [];
975-
while ($usedSchema = array_shift($usedSchemas)) {
976-
if (!str_starts_with((string)$usedSchema, '#/components/schemas/')) {
977+
while ($usedRef = array_shift($usedRefs)) {
978+
if (!str_starts_with((string)$usedRef, '#/components/schemas/')) {
977979
continue;
978980
}
979981

980-
$schemaName = substr((string)$usedSchema, strlen('#/components/schemas/'));
982+
$schemaName = substr((string)$usedRef, strlen('#/components/schemas/'));
981983

982984
if (!isset($schemas[$schemaName])) {
983985
Logger::error('app', "Schema $schemaName used by scope $scope is not defined");
@@ -986,11 +988,12 @@
986988
$newRefs = Helpers::collectUsedRefs($schemas[$schemaName]);
987989
foreach ($newRefs as $newRef) {
988990
if (!isset($scopedSchemas[substr((string)$newRef, strlen('#/components/schemas/'))])) {
989-
$usedSchemas[] = $newRef;
991+
$usedRefs[] = $newRef;
990992
}
991993
}
992994

993995
$scopedSchemas[$schemaName] = $schemas[$schemaName];
996+
$usedSchemas[] = $schemaName;
994997
}
995998

996999
if (isset($schemas['Capabilities'])) {
@@ -1031,6 +1034,11 @@
10311034
Logger::info('app', 'Generated scope ' . $scope . ' with ' . $pathsCount . ' routes!');
10321035
}
10331036

1037+
$unusedSchemas = array_diff(array_keys($schemas), $usedSchemas);
1038+
if ($unusedSchemas !== []) {
1039+
Logger::error('app', 'Unused schemas: ' . implode(', ', $unusedSchemas));
1040+
}
1041+
10341042
if (Logger::$errorCount > 0) {
10351043
Logger::panic('app', 'Encountered ' . Logger::$errorCount . ' errors that need to be fixed!');
10361044
}

tests/lib/Capabilities.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Notifications;
11+
12+
use OCP\Capabilities\ICapability;
13+
14+
class Capabilities implements ICapability {
15+
/**
16+
* @return array{test: array{a: int}}
17+
*/
18+
public function getCapabilities(): array {
19+
return [];
20+
}
21+
}

tests/lib/PublicCapabilities.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Notifications;
11+
12+
use OCP\Capabilities\IPublicCapability;
13+
14+
class PublicCapabilities implements IPublicCapability {
15+
/**
16+
* @return array{test: array{b: string}}
17+
*/
18+
public function getCapabilities(): array {
19+
return [];
20+
}
21+
}

tests/openapi-administration.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020
}
2121
},
2222
"schemas": {
23+
"Capabilities": {
24+
"type": "object",
25+
"required": [
26+
"test"
27+
],
28+
"properties": {
29+
"test": {
30+
"type": "object",
31+
"required": [
32+
"a"
33+
],
34+
"properties": {
35+
"a": {
36+
"type": "integer",
37+
"format": "int64"
38+
}
39+
}
40+
}
41+
}
42+
},
2343
"OCSMeta": {
2444
"type": "object",
2545
"required": [
@@ -44,6 +64,25 @@
4464
}
4565
}
4666
},
67+
"PublicCapabilities": {
68+
"type": "object",
69+
"required": [
70+
"test"
71+
],
72+
"properties": {
73+
"test": {
74+
"type": "object",
75+
"required": [
76+
"b"
77+
],
78+
"properties": {
79+
"b": {
80+
"type": "string"
81+
}
82+
}
83+
}
84+
}
85+
},
4786
"PushDevice": {
4887
"allOf": [
4988
{

tests/openapi-ex_app.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020
}
2121
},
2222
"schemas": {
23+
"Capabilities": {
24+
"type": "object",
25+
"required": [
26+
"test"
27+
],
28+
"properties": {
29+
"test": {
30+
"type": "object",
31+
"required": [
32+
"a"
33+
],
34+
"properties": {
35+
"a": {
36+
"type": "integer",
37+
"format": "int64"
38+
}
39+
}
40+
}
41+
}
42+
},
2343
"OCSMeta": {
2444
"type": "object",
2545
"required": [
@@ -43,6 +63,25 @@
4363
"type": "string"
4464
}
4565
}
66+
},
67+
"PublicCapabilities": {
68+
"type": "object",
69+
"required": [
70+
"test"
71+
],
72+
"properties": {
73+
"test": {
74+
"type": "object",
75+
"required": [
76+
"b"
77+
],
78+
"properties": {
79+
"b": {
80+
"type": "string"
81+
}
82+
}
83+
}
84+
}
4685
}
4786
}
4887
},

tests/openapi-federation.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020
}
2121
},
2222
"schemas": {
23+
"Capabilities": {
24+
"type": "object",
25+
"required": [
26+
"test"
27+
],
28+
"properties": {
29+
"test": {
30+
"type": "object",
31+
"required": [
32+
"a"
33+
],
34+
"properties": {
35+
"a": {
36+
"type": "integer",
37+
"format": "int64"
38+
}
39+
}
40+
}
41+
}
42+
},
2343
"OCSMeta": {
2444
"type": "object",
2545
"required": [
@@ -43,6 +63,25 @@
4363
"type": "string"
4464
}
4565
}
66+
},
67+
"PublicCapabilities": {
68+
"type": "object",
69+
"required": [
70+
"test"
71+
],
72+
"properties": {
73+
"test": {
74+
"type": "object",
75+
"required": [
76+
"b"
77+
],
78+
"properties": {
79+
"b": {
80+
"type": "string"
81+
}
82+
}
83+
}
84+
}
4685
}
4786
}
4887
},

tests/openapi-full.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020
}
2121
},
2222
"schemas": {
23+
"Capabilities": {
24+
"type": "object",
25+
"required": [
26+
"test"
27+
],
28+
"properties": {
29+
"test": {
30+
"type": "object",
31+
"required": [
32+
"a"
33+
],
34+
"properties": {
35+
"a": {
36+
"type": "integer",
37+
"format": "int64"
38+
}
39+
}
40+
}
41+
}
42+
},
2343
"Collection": {
2444
"type": "array",
2545
"items": {
@@ -179,6 +199,25 @@
179199
}
180200
}
181201
},
202+
"PublicCapabilities": {
203+
"type": "object",
204+
"required": [
205+
"test"
206+
],
207+
"properties": {
208+
"test": {
209+
"type": "object",
210+
"required": [
211+
"b"
212+
],
213+
"properties": {
214+
"b": {
215+
"type": "string"
216+
}
217+
}
218+
}
219+
}
220+
},
182221
"PushDevice": {
183222
"allOf": [
184223
{

tests/openapi.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020
}
2121
},
2222
"schemas": {
23+
"Capabilities": {
24+
"type": "object",
25+
"required": [
26+
"test"
27+
],
28+
"properties": {
29+
"test": {
30+
"type": "object",
31+
"required": [
32+
"a"
33+
],
34+
"properties": {
35+
"a": {
36+
"type": "integer",
37+
"format": "int64"
38+
}
39+
}
40+
}
41+
}
42+
},
2343
"Collection": {
2444
"type": "array",
2545
"items": {
@@ -179,6 +199,25 @@
179199
}
180200
}
181201
},
202+
"PublicCapabilities": {
203+
"type": "object",
204+
"required": [
205+
"test"
206+
],
207+
"properties": {
208+
"test": {
209+
"type": "object",
210+
"required": [
211+
"b"
212+
],
213+
"properties": {
214+
"b": {
215+
"type": "string"
216+
}
217+
}
218+
}
219+
}
220+
},
182221
"RequestProperty": {
183222
"type": "object",
184223
"required": [

0 commit comments

Comments
 (0)