Skip to content

Commit 138b0a5

Browse files
authored
Perform github path check during validation, rather than metadata parsing. (#81)
Downstream users of DocGen often load the metadata separately from the original file, which is a problem when the excerpt github link checks against an actual path.
1 parent 4517bf6 commit 138b0a5

File tree

3 files changed

+82
-56
lines changed

3 files changed

+82
-56
lines changed

aws_doc_sdk_examples_tools/doc_gen.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ def validate(self):
256256
sdk.validate(self.errors)
257257
for service in self.services.values():
258258
service.validate(self.errors)
259+
for example in self.examples.values():
260+
example.validate(self.errors, self.root)
259261
validate_metadata(self.root, self.errors)
260262
validate_no_duplicate_api_examples(self.examples.values(), self.errors)
261263
validate_snippets(

aws_doc_sdk_examples_tools/metadata.py

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ def from_yaml(cls, yaml: Any) -> tuple["Excerpt", MetadataErrors]:
7373

7474
return (cls(description, snippet_tags, snippet_files, genai), errors)
7575

76+
def validate(self, errors: MetadataErrors):
77+
pass
78+
7679

7780
@dataclass
7881
class Version:
@@ -112,23 +115,6 @@ def from_yaml(
112115
if sdkguide.startswith("https://docs.aws.amazon.com"):
113116
errors.append(metadata_errors.InvalidSdkGuideStart(guide=sdkguide))
114117

115-
if github is not None:
116-
_, ext = splitext(github)
117-
if ext != "":
118-
errors.append(
119-
metadata_errors.InvalidGithubLink(
120-
link=github, sdk_version=sdk_version
121-
)
122-
)
123-
elif github.startswith("http"):
124-
pass # Tributaries specify full GitHub path. Consider passing in GitHub root from tributaries and doing a full check at some point.
125-
elif not (root / github).exists():
126-
errors.append(
127-
metadata_errors.MissingGithubLink(
128-
link=github, sdk_version=sdk_version, root=root
129-
)
130-
)
131-
132118
excerpts = []
133119
for excerpt in yaml.get("excerpts", []):
134120
parsed, parse_errors = Excerpt.from_yaml(excerpt)
@@ -173,6 +159,28 @@ def from_yaml(
173159
errors,
174160
)
175161

162+
def validate(self, errors: MetadataErrors, root: Path):
163+
github = self.github
164+
if github is not None:
165+
_, ext = splitext(github)
166+
if ext != "":
167+
errors.append(
168+
metadata_errors.InvalidGithubLink(
169+
link=github, sdk_version=self.sdk_version
170+
)
171+
)
172+
elif github.startswith("http"):
173+
pass # Tributaries specify full GitHub path. Consider passing in GitHub root from tributaries and doing a full check at some point.
174+
elif not (root / github).exists():
175+
errors.append(
176+
metadata_errors.MissingGithubLink(
177+
link=github, sdk_version=self.sdk_version, root=root
178+
)
179+
)
180+
181+
for excerpt in self.excerpts:
182+
excerpt.validate(errors)
183+
176184

177185
@dataclass
178186
class Language:
@@ -242,6 +250,15 @@ def from_yaml(
242250

243251
return cls(name, property, versions), errors
244252

253+
def validate(self, errors: MetadataErrors, root: Path):
254+
errs = MetadataErrors()
255+
for version in self.versions:
256+
version.validate(errs, root)
257+
for error in errs:
258+
if isinstance(error, MetadataParseError):
259+
error.language = self.name
260+
errors.extend(errs)
261+
245262

246263
@dataclass
247264
class Example:
@@ -394,6 +411,15 @@ def from_yaml(
394411
errors,
395412
)
396413

414+
def validate(self, errors: MetadataErrors, root: Path):
415+
errs = MetadataErrors()
416+
for language in self.languages.values():
417+
language.validate(errs, root)
418+
for error in errs:
419+
error.file = self.file
420+
error.id = self.id
421+
errors.extend(errs)
422+
397423

398424
def parse_services(
399425
yaml: Any, errors: MetadataErrors, known_services: Dict[str, Service]

aws_doc_sdk_examples_tools/metadata_test.py

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import pytest
99
import yaml
1010
from pathlib import Path
11-
from typing import List, Set, Tuple, Optional
11+
from typing import List, Set, Tuple
1212

1313
from . import metadata_errors
1414
from .metadata_errors import MetadataErrors, ExampleMergeConflict
@@ -32,13 +32,9 @@
3232
def load(
3333
path: Path, doc_gen: DocGen, blocks: Set[str] = set()
3434
) -> Tuple[List[Example], metadata_errors.MetadataErrors]:
35-
root = Path(__file__).parent
36-
filename = root / "test_resources" / path
37-
with filename.open() as file:
35+
with path.open() as file:
3836
meta = yaml.safe_load(file)
39-
return parse(
40-
filename, meta, doc_gen.sdks, doc_gen.services, blocks, doc_gen.validation
41-
)
37+
return parse(path, meta, doc_gen.sdks, doc_gen.services, blocks, doc_gen.validation)
4238

4339

4440
SERVICES = {
@@ -378,14 +374,6 @@ def test_parse_strict_title_errors():
378374
file=Path("test_cpp.yaml"),
379375
id="medical-imaging_BadBasics",
380376
),
381-
metadata_errors.MissingGithubLink(
382-
file=Path("test_cpp.yaml"),
383-
id="medical-imaging_BadBasics",
384-
language="C++",
385-
sdk_version=1,
386-
link="cpp/example_code/medical-imaging",
387-
root=Path("."),
388-
),
389377
]
390378
assert expected == [*errors]
391379

@@ -464,7 +452,7 @@ def test_parse_cross():
464452

465453
def test_verify_load_successful():
466454
actual, errors = load(
467-
Path(__file__).parent / "test_resources/valid_metadata.yaml",
455+
TEST_RESOURCES_PATH / "valid_metadata.yaml",
468456
DOC_GEN,
469457
set(["test block"]),
470458
)
@@ -595,15 +583,14 @@ def test_verify_load_successful():
595583
assert actual[0] == example
596584

597585

598-
EMPTY_METADATA_PATH = Path(__file__).parent / "test_resources/empty_metadata.yaml"
599-
ERRORS_METADATA_PATH = Path(__file__).parent / "test_resources/errors_metadata.yaml"
600-
FORMATTER_METADATA_PATH = (
601-
Path(__file__).parent / "test_resources/formaterror_metadata.yaml"
602-
)
586+
TEST_RESOURCES_PATH = Path(__file__).parent / "test_resources"
587+
EMPTY_METADATA_PATH = TEST_RESOURCES_PATH / "empty_metadata.yaml"
588+
ERRORS_METADATA_PATH = TEST_RESOURCES_PATH / "errors_metadata.yaml"
589+
FORMATTER_METADATA_PATH = TEST_RESOURCES_PATH / "formaterror_metadata.yaml"
603590

604591

605592
@pytest.mark.parametrize(
606-
"filename,expected_errors",
593+
"filename,expected_errors,validation_errors",
607594
[
608595
(
609596
"empty_metadata.yaml",
@@ -620,6 +607,7 @@ def test_verify_load_successful():
620607
svcs=[],
621608
),
622609
],
610+
[],
623611
),
624612
(
625613
"errors_metadata.yaml",
@@ -641,14 +629,6 @@ def test_verify_load_successful():
641629
guide="https://docs.aws.amazon.com/absolute/link-to-my-guide",
642630
sdk_version=1,
643631
),
644-
metadata_errors.MissingGithubLink(
645-
file=ERRORS_METADATA_PATH,
646-
id="sqs_WrongServiceSlug",
647-
language="Perl",
648-
sdk_version=1,
649-
link="perl/example_code/medical-imaging",
650-
root=ERRORS_METADATA_PATH.parent,
651-
),
652632
metadata_errors.MissingBlockContentAndExcerpt(
653633
file=ERRORS_METADATA_PATH,
654634
id="sqs_WrongServiceSlug",
@@ -691,13 +671,6 @@ def test_verify_load_successful():
691671
id="medical-imaging_TestExample2",
692672
service="garbled",
693673
),
694-
metadata_errors.InvalidGithubLink(
695-
file=ERRORS_METADATA_PATH,
696-
id="medical-imaging_TestExample2",
697-
language="Java",
698-
sdk_version=2,
699-
link="github/link/to/README.md",
700-
),
701674
metadata_errors.FieldError(
702675
file=ERRORS_METADATA_PATH,
703676
id="medical-imaging_TestExample2",
@@ -730,6 +703,23 @@ def test_verify_load_successful():
730703
id="medical-imagingBadFormat",
731704
),
732705
],
706+
[
707+
metadata_errors.MissingGithubLink(
708+
file=ERRORS_METADATA_PATH,
709+
id="sqs_WrongServiceSlug",
710+
language="Perl",
711+
sdk_version=1,
712+
link="perl/example_code/medical-imaging",
713+
root=TEST_RESOURCES_PATH,
714+
),
715+
metadata_errors.InvalidGithubLink(
716+
file=ERRORS_METADATA_PATH,
717+
id="medical-imaging_TestExample2",
718+
language="Java",
719+
sdk_version=2,
720+
link="github/link/to/README.md",
721+
),
722+
],
733723
),
734724
(
735725
"formaterror_metadata.yaml",
@@ -746,14 +736,22 @@ def test_verify_load_successful():
746736
service="garbage",
747737
),
748738
],
739+
[],
749740
),
750741
],
751742
)
752743
def test_common_errors(
753-
filename: str, expected_errors: List[metadata_errors.MetadataError]
744+
filename: str,
745+
expected_errors: List[metadata_errors.MetadataError],
746+
validation_errors: List[metadata_errors.MetadataError],
754747
):
755-
_, actual = load(Path(filename), DOC_GEN, set(["test/block", "cross_block.xml"]))
748+
root = TEST_RESOURCES_PATH / filename
749+
examples, actual = load(root, DOC_GEN, set(["test/block", "cross_block.xml"]))
756750
assert expected_errors == [*actual]
751+
validations = MetadataErrors()
752+
for example in examples:
753+
example.validate(validations, root.parent)
754+
assert validation_errors == [*validations]
757755

758756

759757
TEST_SERVICES = {"test": {"Test", "Test2", "Test3", "1"}}

0 commit comments

Comments
 (0)