Skip to content

Commit a26c352

Browse files
wbambergrichvdh
authored andcommitted
Merge pull request #1 from matrix-org/anoa/support-rendered-data
Reinstate and fix schema validation files
2 parents 7fed40a + 3c66e14 commit a26c352

File tree

6 files changed

+167
-27
lines changed

6 files changed

+167
-27
lines changed

.circleci/config.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ gendoc: &gendoc
55
scripts/gendoc.py
66
77
genswagger: &genswagger
8-
name: Generate the swagger
8+
name: Validate sources and generate swagger json
99
command: |
1010
source /env/bin/activate
11+
scripts/check-swagger-sources.py
1112
scripts/dump-swagger.py
1213
1314
buildswaggerui: &buildswaggerui
@@ -27,10 +28,7 @@ checkexamples: &checkexamples
2728
name: Check Event Examples
2829
command: |
2930
source /env/bin/activate
30-
cd event-schemas
31-
./check_examples.py
32-
cd ../api
33-
./check_examples.py
31+
scripts/check-event-schema-examples.py
3432
3533
genmatrixassets: &genmatrixassets
3634
name: Generate/Verify matrix.org assets
@@ -41,9 +39,9 @@ genmatrixassets: &genmatrixassets
4139
validateapi: &validateapi
4240
name: Validate OpenAPI specifications
4341
command: |
44-
cd api
42+
cd scripts
4543
npm install
46-
node validator.js -s "client-server"
44+
node validator.js -s "../data/api/client-server"
4745
4846
buildspeculator: &buildspeculator
4947
name: Build Speculator

event-schemas/check_examples.py renamed to scripts/check-event-schema-examples.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,14 @@ def check_example_dir(exampledir, schemadir):
128128

129129

130130
if __name__ == '__main__':
131+
# Get the directory that this script is residing in
132+
script_directory = os.path.dirname(os.path.realpath(__file__))
133+
134+
# Resolve the directories to check, relative to the script path
135+
examples_directory = os.path.join(script_directory, "../event-schemas/examples")
136+
schema_directory = os.path.join(script_directory, "../event-schemas/schema")
137+
131138
try:
132-
check_example_dir("examples", "schema")
139+
check_example_dir(examples_directory, schema_directory)
133140
except:
134141
sys.exit(1)

api/check_examples.py renamed to scripts/check-swagger-sources.py

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,36 @@ def check_swagger_file(filepath):
108108

109109

110110
def resolve_references(path, schema):
111+
"""Recurse through a given schema until we find a $ref key. Upon doing so,
112+
check that the referenced file exists, then load it up and check all of the
113+
references in that file. Continue on until we've hit all dead ends.
114+
115+
$ref values are deleted from schemas as they are validated, to prevent
116+
duplicate work.
117+
"""
111118
if isinstance(schema, dict):
112119
# do $ref first
113120
if '$ref' in schema:
114-
value = schema['$ref']
115-
path = os.path.abspath(os.path.join(os.path.dirname(path), value))
116-
ref = load_file("file://" + path)
117-
result = resolve_references(path, ref)
121+
# Pull the referenced filepath from the schema
122+
referenced_file = schema['$ref']
123+
124+
# Referenced filepaths are relative, so take the current path's
125+
# directory and append the relative, referenced path to it.
126+
inner_path = os.path.join(os.path.dirname(path), referenced_file)
127+
128+
# Then convert the path (which may contiain '../') into a
129+
# normalised, absolute path
130+
inner_path = os.path.abspath(inner_path)
131+
132+
# Load the referenced file
133+
ref = load_file("file://" + inner_path)
134+
135+
# Check that the references in *this* file are valid
136+
result = resolve_references(inner_path, ref)
137+
138+
# They were valid, and so were the sub-references. Delete
139+
# the reference here to ensure we don't pass over it again
140+
# when checking other files
118141
del schema['$ref']
119142
else:
120143
result = {}
@@ -143,15 +166,22 @@ def load_file(path):
143166

144167

145168
if __name__ == '__main__':
146-
paths = sys.argv[1:]
147-
if not paths:
148-
paths = []
149-
for (root, dirs, files) in os.walk(os.curdir):
150-
for filename in files:
151-
if filename.endswith(".yaml"):
152-
paths.append(os.path.join(root, filename))
153-
for path in paths:
154-
try:
155-
check_swagger_file(path)
156-
except Exception as e:
157-
raise ValueError("Error checking file %r" % (path,), e)
169+
# Get the directory that this script is residing in
170+
script_directory = os.path.dirname(os.path.realpath(__file__))
171+
172+
# Resolve the directory containing the swagger sources,
173+
# relative to the script path
174+
source_files_directory = os.path.realpath(os.path.join(script_directory, "../data"))
175+
176+
# Walk the source path directory, looking for YAML files to check
177+
for (root, dirs, files) in os.walk(source_files_directory):
178+
for filename in files:
179+
if not filename.endswith(".yaml"):
180+
continue
181+
182+
path = os.path.join(root, filename)
183+
184+
try:
185+
check_swagger_file(path)
186+
except Exception as e:
187+
raise ValueError("Error checking file %s" % (path,), e)

scripts/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "swagger-cli-validator",
3+
"version": "0.0.1",
4+
"description": "",
5+
"main": "validator.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"author": "",
10+
"license": "ISC",
11+
"dependencies": {
12+
"nopt": "^3.0.2",
13+
"swagger-parser": "^3.2.1"
14+
}
15+
}

scripts/test-and-build.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ virtualenv -p python3 env
1111
python --version
1212
pip --version
1313

14+
# Install python dependencies
1415
pip install -r scripts/requirements.txt
1516

17+
# Install node dependencies
18+
npm install --prefix=scripts
19+
1620
# do sanity checks on the examples and swagger
17-
(cd event-schemas/ && ./check_examples.py)
18-
(cd api && ./check_examples.py)
19-
(cd api && npm install && node validator.js -s "client-server")
21+
scripts/check-event-schema-examples.py
22+
scripts/check-swagger-sources.py
23+
node scripts/validator.js --schema "data/api/client-server"
2024

2125
: ${GOPATH:=${WORKSPACE}/.gopath}
2226
mkdir -p "${GOPATH}"

scripts/validator.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"use strict";
2+
var fs = require("fs");
3+
var nopt = require("nopt");
4+
var parser = require("swagger-parser");
5+
var path = require("path");
6+
7+
var opts = nopt({
8+
"help": Boolean,
9+
"schema": path
10+
}, {
11+
"h": "--help",
12+
"s": "--schema"
13+
});
14+
15+
if (opts.help) {
16+
console.log(
17+
"Use swagger-parser to validate against Swagger 2.0\n"+
18+
"Usage:\n"+
19+
" node validator.js -s <schema_file_or_folder>"
20+
);
21+
process.exit(0);
22+
}
23+
if (!opts.schema) {
24+
console.error("No [s]chema specified.");
25+
process.exit(1);
26+
}
27+
28+
29+
var errFn = function(err, api) {
30+
if (!err) {
31+
return;
32+
}
33+
console.error(err);
34+
process.exit(1);
35+
};
36+
37+
/**
38+
* @brief Produce a handler for parser.validate().
39+
* Recommended usage: `parser.validate(filename, makeHandler(filename));`
40+
* or `parser.validate(schema, makeHandler());`.
41+
* @param scope - usually a filename, this will be used to denote
42+
* an (in)valid schema in console output; "Schema" if undefined
43+
* @returns {function} the handler that can be passed to parser.validate
44+
*/
45+
function makeHandler(scope) {
46+
if (!scope)
47+
scope = "Schema";
48+
return function(err, api, metadata) {
49+
if (err) {
50+
console.error("%s is not valid.", scope || "Schema");
51+
errFn(err, api, metadata); // Won't return
52+
}
53+
54+
Object.keys(api.paths).forEach(function (endpoint) {
55+
var operationsMap = api.paths[endpoint];
56+
Object.keys(operationsMap).forEach(function (verb) {
57+
if (!operationsMap[verb]["operationId"]) {
58+
console.error("%s is not valid", scope);
59+
errFn("operationId is missing in " + endpoint + ", verb " + verb, api);
60+
}
61+
})
62+
});
63+
64+
console.log("%s is valid.", scope);
65+
}
66+
}
67+
68+
var isDir = fs.lstatSync(opts.schema).isDirectory();
69+
if (isDir) {
70+
console.log("Checking directory %s for .yaml files...", opts.schema);
71+
fs.readdir(opts.schema, function(err, files) {
72+
if (err) {
73+
errFn(err); // Won't return
74+
}
75+
files.forEach(function(f) {
76+
var suffix = ".yaml";
77+
if (f.indexOf(suffix, f.length - suffix.length) > 0) {
78+
parser.validate(path.join(opts.schema, f), makeHandler(f));
79+
}
80+
});
81+
});
82+
}
83+
else{
84+
parser.validate(opts.schema, makeHandler(opts.schema));
85+
}
86+

0 commit comments

Comments
 (0)