Skip to content

Commit 9cc02bc

Browse files
metadata.json validator / metadata file adjustments (#184)
* Initial metadata validator * Reduce service name length * dotnet changed to .NET * Updates for serverlessland metadata validation --------- Co-authored-by: Tom Romano <[email protected]>
1 parent a4e8f10 commit 9cc02bc

File tree

16 files changed

+305
-34
lines changed

16 files changed

+305
-34
lines changed
+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
METADATA = {
2+
"$schema": "http://json-schema.org/draft-07/schema",
3+
"$id": "http://example.com/example.json",
4+
"type": "object",
5+
"title": "Sample schema for ServerlessLand metadata.json files",
6+
"description": "This JSON document describes a sub-repo for displaying on ServerlessLand.",
7+
"required": ["title", "description", "content_language","language","type","diagram",
8+
"framework","services","git_repo_url","pattern_source",
9+
"pattern_detail_tabs","authors"],
10+
"properties": {
11+
"title": {
12+
"$id": "#/properties/title",
13+
"type": "string",
14+
"title": "The sub-repo title",
15+
"examples": ["Python Starter Project"],
16+
"maxLength": 128,
17+
"minLength": 10
18+
},
19+
"description": {
20+
"$id": "#/properties/description",
21+
"type": "string",
22+
"title": "The sub-repo description",
23+
"examples": ["This project contains automated test sample code samples for serverless applications written in Python."],
24+
"maxLength": 1028,
25+
"minLength": 10
26+
},
27+
"content_language": {
28+
"$id": "#/properties/content_language",
29+
"type": "string",
30+
"title": "Repository Written Language",
31+
"examples": ["English","Spanish"],
32+
"maxLength": 60,
33+
"minLength": 3
34+
},
35+
"language": {
36+
"$id": "#/properties/language",
37+
"type": "string",
38+
"title": "Repository Programming Language",
39+
"examples": [".NET","Python"],
40+
"pattern": ".NET|Java|Python|Typescript|GO|Rust",
41+
"maxLength": 60,
42+
"minLength": 3
43+
},
44+
"type": {
45+
"$id": "#/properties/type",
46+
"type": "array",
47+
"title": "Test Types Implemented",
48+
"examples": [["Unit"],["Unit","Integration"]],
49+
"minItems": 1,
50+
"uniqueItems": True,
51+
"items": {
52+
"type": "string",
53+
"pattern": "Unit|Integration|Load|Canary",
54+
}
55+
},
56+
"diagram": {
57+
"$id": "#/properties/diagram",
58+
"type": "string",
59+
"title": "Achitecture or Test Diagram for the pattern",
60+
"examples": ["/img/xray.png"],
61+
"maxLength": 2048,
62+
"minLength": 3
63+
},
64+
"framework": {
65+
"$id": "#/properties/framework",
66+
"type": "string",
67+
"title": "Deployment Framework for the pattern",
68+
"examples": ["SAM"],
69+
"pattern": "SAM|Cloudformation|CDK",
70+
"maxLength": 60,
71+
"minLength": 3
72+
},
73+
"services": {
74+
"$id": "#/properties/services",
75+
"type": "array",
76+
"title": "AWS Services used in the pattern",
77+
"examples": [["apigw","lambda","dynamodb"]],
78+
"minItems": 1,
79+
"uniqueItems": True,
80+
"items": {
81+
"type": "string",
82+
"minLength": 2
83+
}
84+
},
85+
"git_repo_url": {
86+
"$id": "#/properties/git_repo_url",
87+
"type": "string",
88+
"title": "URL of the git repo",
89+
"examples": ["https://github.com/aws-samples/serverless-test-samples"],
90+
"pattern": "https://github.com/aws-samples/serverless-test-samples|https://github.com/aws-samples/*",
91+
"maxLength": 2048,
92+
"minLength": 3
93+
},
94+
"pattern_source": {
95+
"$id": "#/properties/pattern_source",
96+
"type": "string",
97+
"title": "Contributor of the the pattern",
98+
"examples": ["AWS"],
99+
"pattern": "AWS|Customer",
100+
"maxLength": 60,
101+
"minLength": 3
102+
},
103+
"pattern_detail_tabs": {
104+
"$id": "#/properties/pattern_detail_tabs",
105+
"type": "array",
106+
"title": "Detail links to key files, from sub-repo root",
107+
"minItems": 1,
108+
"uniqueItems": True,
109+
"items": {
110+
"type": "object",
111+
"required": ["title","filepath"],
112+
"properties": {
113+
"title": {
114+
"$id": "#/properties/pattern_detail_tabs/properties/title",
115+
"type": "string",
116+
"title": "Title of the key file",
117+
"examples": ["Application Code","Unit Tests - Emulator"],
118+
"maxLength": 128,
119+
"minLength": 3
120+
},
121+
"filepath": {
122+
"$id": "#/properties/pattern_detail_tabs/properties/filepath",
123+
"type": "string",
124+
"title": "File path of the key file from sub-project root",
125+
"examples": ["/src/app.py","/tests/unit/local_emulator_test.py"],
126+
"maxLength": 128,
127+
"minLength": 3
128+
}
129+
}
130+
}
131+
},
132+
"authors": {
133+
"$id": "#/properties/authors",
134+
"type": "array",
135+
"title": "About the authors",
136+
"minItems": 1,
137+
"uniqueItems": True,
138+
"items": {
139+
"type": "object",
140+
"required": ["name","bio"],
141+
"properties": {
142+
"name": {
143+
"$id": "#/properties/authors/properties/name",
144+
"type": "string",
145+
"title": "Author Name",
146+
"examples": ["Sara Tester","Joe Programmer"],
147+
"maxLength": 2048,
148+
"minLength": 3
149+
},
150+
"image": {
151+
"$id": "#/properties/authors/properties/image",
152+
"type": "string",
153+
"title": "URL to a hosted image of the author",
154+
"examples": ["https://www.linkedin.com/in/exampleperson/mypicture.png"],
155+
"maxLength": 4096,
156+
"minLength": 3,
157+
"pattern": "https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)"
158+
}
159+
,
160+
"bio": {
161+
"$id": "#/properties/authors/properties/bio",
162+
"type": "string",
163+
"title": "More about the author",
164+
"examples": ["Principal Solutions Architect at AWS"],
165+
"maxLength": 2048,
166+
"minLength": 3
167+
}
168+
,
169+
"linkedin": {
170+
"$id": "#/properties/authors/properties/linkedin",
171+
"type": "string",
172+
"title": "URL to LinkedIn Account",
173+
"examples": [ "https://www.linkedin.com/in/exampleperson/"],
174+
"maxLength": 4096,
175+
"minLength": 3,
176+
"pattern": "https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)"
177+
}
178+
,
179+
"twitter": {
180+
"$id": "#/properties/authors/properties/twitter",
181+
"type": "string",
182+
"title": "Twitter handle for author",
183+
"examples": ["https://twitter.com/exampleperson"],
184+
"maxLength": 4096,
185+
"minLength": 3,
186+
"pattern": "https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)"
187+
}
188+
}
189+
}
190+
},
191+
192+
},
193+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Metadata Validation
3+
4+
This script validates the metadata for presenting the code sample on serverlessland.com.
5+
It is used in a github action to verify the proper file format for
6+
{language-test-samples}/{sub-project}/metadata.json
7+
8+
The script is called with the {language-test-samples}/{sub-project} as the only arguement
9+
10+
Example (from serverless-test-samples):
11+
12+
python3 .github/METADATA/metadata_json_validator.py python-test-samples/apigw-lambda
13+
14+
"""
15+
16+
from os import path
17+
import json
18+
import argparse
19+
from aws_lambda_powertools.utilities.validation import SchemaValidationError, validate
20+
from metadata_json_schema import METADATA
21+
22+
23+
def validate_metadata_json(metadata_json_filename: str) -> dict:
24+
"""
25+
Run Validations for the metadata schema
26+
:param: metadata_json_filename - relative path from the CWD to the metadata.json file to analyze
27+
:return: Dict with first error
28+
"""
29+
try:
30+
31+
with open(metadata_json_filename,"r", encoding="utf-8") as metadata_object:
32+
metadata_contents = json.load(metadata_object)
33+
34+
validate(event=metadata_contents, schema=METADATA)
35+
36+
diagram_path = path.dirname(metadata_json_filename) + metadata_contents["diagram"]
37+
if path.isfile(diagram_path) is False:
38+
raise FileNotFoundError("Invalid diagram path: " + metadata_contents["diagram"])
39+
40+
if "https://github.com/aws-samples/serverless-test-samples" in metadata_contents["git_repo_url"]:
41+
for pattern_detail in metadata_contents["pattern_detail_tabs"]:
42+
detail_path = path.dirname(metadata_json_filename) + pattern_detail["filepath"]
43+
if path.isfile(detail_path) is False:
44+
raise FileNotFoundError("Invalid detail path: " + pattern_detail["filepath"])
45+
else:
46+
print( "External repo detected, bypassing code path checks.")
47+
48+
return {"body": "OK", "statusCode": 200}
49+
except FileNotFoundError as exception:
50+
return {"body": str(exception), "statusCode": 404}
51+
except SchemaValidationError as exception:
52+
# SchemaValidationError indicates where a data mismatch is
53+
return {"body": str(exception), "statusCode": 406}
54+
except Exception as exception:
55+
return {"body": str(exception), "statusCode": 422}
56+
57+
if __name__ == "__main__":
58+
parser = argparse.ArgumentParser(
59+
prog='metadata_json_validator.py',
60+
description='Validate metadata.json for presenting the code sample on serverlessland.com.'
61+
)
62+
63+
parser.add_argument('sub_repo_path',
64+
type=str,
65+
help="Path to the sub-repo from the project root." + \
66+
"Example: python-test-samples/apigw-lambda'"
67+
)
68+
args = parser.parse_args()
69+
70+
metadata_filename = path.join(args.sub_repo_path, "metadata.json")
71+
print(f"Validating: {metadata_filename}")
72+
print(validate_metadata_json(metadata_filename))

.github/METADATA/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
aws_lambda_powertools
Loading

dotnet-test-samples/apigw-lambda-ddb/metadata.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
"content_language": "English",
55
"language": ".NET",
66
"type": ["Unit", "Integration"],
7-
"diagram": "../docs/apigw-lambda-ddb.jpg",
7+
"diagram": "/img/apigw-lambda-ddb.jpg",
88
"git_repo_url": "https://github.com/aws-samples/serverless-test-samples",
99
"framework": "SAM",
1010
"services": ["apigw", "lambda", "dynamodb"],
11+
"pattern_source": "AWS",
1112
"pattern_detail_tabs": [
1213
{
13-
"title": "Application Code",
14-
"filepath": "/src/"
14+
"title": "Application Code Example (GetProduct)",
15+
"filepath": "/src/GetProduct/Function.cs"
1516
},
1617
{
1718
"title": "Unit Tests",
Loading

dotnet-test-samples/apigw-lambda-list-s3-buckets/metadata.json

+10-5
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,27 @@
44
"content_language": "English",
55
"language": ".NET",
66
"type": ["Unit", "Integration"],
7-
"diagram": "../docs/apigw-lambda-list-s3-buckets.png",
7+
"diagram": "/img/apigw-lambda-list-s3-buckets.png",
88
"git_repo_url": "https://github.com/aws-samples/serverless-test-samples",
99
"framework": "SAM",
1010
"services": ["apigw", "lambda", "s3"],
11+
"pattern_source": "AWS",
1112
"pattern_detail_tabs": [
1213
{
1314
"title": "Application Code",
14-
"filepath": "/src/"
15+
"filepath": "/src/ServerlessTestSamples/Function.cs"
1516
},
1617
{
17-
"title": "Unit Tests",
18-
"filepath": "/tests/ServerlessTestSamples.UnitTest/ApiTests.UnitTest"
18+
"title": "Unit Tests - Mock Business Logic",
19+
"filepath": "/tests/ServerlessTestSamples.UnitTest/MockBusinessLogicTests.cs"
20+
},
21+
{
22+
"title": "Unit Tests - Mock SDK",
23+
"filepath": "/tests/ServerlessTestSamples.UnitTest/MockSdkTests.cs"
1924
},
2025
{
2126
"title": "Integration Test",
22-
"filepath": "/tests/ServerlessTestSamples.IntegrationTest"
27+
"filepath": "/tests/ServerlessTestSamples.IntegrationTest/IntegrationTest.cs"
2328
}
2429
],
2530
"authors": [
Loading

dotnet-test-samples/hexagonal-architecture/metadata.json

+6-5
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,23 @@
44
"content_language": "English",
55
"language": ".NET",
66
"type": ["Unit", "Integration"],
7-
"diagram": "../docs/hexagonal-architecture.png.png",
7+
"diagram": "/img/hexagonal-architecture.png",
88
"git_repo_url": "https://github.com/aws-samples/serverless-test-samples",
9+
"pattern_source": "AWS",
910
"framework": "SAM",
1011
"services": ["apigw", "lambda", "dynamoDB"],
1112
"pattern_detail_tabs": [
1213
{
13-
"title": "Application Code",
14-
"filepath": "/src/"
14+
"title": "Application Code Example (GetStock Functions)",
15+
"filepath": "/src/GetStock/Functions.cs"
1516
},
1617
{
1718
"title": "Unit Tests",
18-
"filepath": "/tests/GetStock.UnitTest"
19+
"filepath": "/tests/GetStock.UnitTest/FunctionsTests.cs"
1920
},
2021
{
2122
"title": "Integration Test",
22-
"filepath": "/tests/GetStock.IntegrationTests"
23+
"filepath": "/tests/GetStock.IntegrationTest/Usings.cs"
2324
}
2425
],
2526
"authors": [
Loading

dotnet-test-samples/sqs-lambda/metadata.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
"content_language": "English",
55
"language": ".NET",
66
"type": ["Unit", "Integration"],
7-
"diagram": "../docs/sqs-lambda.png",
7+
"diagram": "/img/sqs-lambda.png",
88
"git_repo_url": "https://github.com/aws-samples/serverless-test-samples",
99
"framework": "SAM",
1010
"services": ["sqs", "lambda", "dynamodb"],
11+
"pattern_source": "AWS",
1112
"pattern_detail_tabs": [
1213
{
1314
"title": "Application Code",

0 commit comments

Comments
 (0)