Skip to content

Commit 67fc3f9

Browse files
committed
Beginning of manifest validations using SHACL
Only validates some fields of RDF tests for now
1 parent 7ad71f6 commit 67fc3f9

3 files changed

Lines changed: 108 additions & 0 deletions

File tree

.github/workflows/validate.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: validate
2+
on:
3+
push:
4+
branches: [ main ]
5+
pull_request:
6+
branches: [ main ]
7+
8+
jobs:
9+
validate_manifest:
10+
name: python
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v5
15+
- uses: astral-sh/setup-uv@v7
16+
- run: uv run validate_manifest.py

ns/shapes.ttl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# SHACL shapes for tests
2+
3+
PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#>
4+
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
5+
PREFIX rdft: <http://www.w3.org/ns/rdftest#>
6+
PREFIX sh: <http://www.w3.org/ns/shacl#>
7+
8+
[
9+
a sh:NodeShape ;
10+
sh:targetClass mf:Manifest ;
11+
sh:property [
12+
sh:path mf:include ;
13+
sh:maxCount 1
14+
] ;
15+
sh:property [
16+
sh:path mf:entries ;
17+
sh:maxCount 1
18+
]
19+
] .
20+
21+
[
22+
a sh:NodeShape ;
23+
sh:targetClass rdft:Test ;
24+
sh:property [
25+
sh:path mf:action ;
26+
sh:nodeKind sh:IRI ;
27+
sh:maxCount 1
28+
] ;
29+
sh:property [
30+
sh:path mf:result ;
31+
sh:or ( [ sh:nodeKind sh:IRI ] [ sh:hasValue false ] ) ;
32+
sh:maxCount 1
33+
] ;
34+
sh:property [
35+
sh:path rdft:approval ;
36+
sh:nodeKind sh:IRI ;
37+
sh:in (rdft:Approved rdft:Proposed rdft:Rejected rdft:NotClassified) ; # TODO: rdft:NotClassified is not in the vocabulary but used
38+
sh:maxCount 1
39+
]
40+
] .

validate_manifest.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# /// script
2+
# dependencies = [
3+
# "pyshacl~=0.30.0",
4+
# ]
5+
# ///
6+
"""
7+
Small Python script to validate manifest files
8+
"""
9+
10+
import os
11+
from pathlib import Path
12+
from pyshacl import validate
13+
14+
repository_root = Path(__file__).parent
15+
shape_path = repository_root / "ns" / "shapes.ttl"
16+
vocab_path = repository_root / "ns" / "rdftest.ttl"
17+
18+
19+
def log_line(message: str, level: str, file: Path | None = None) -> None:
20+
if "GITHUB_ACTIONS" in os.environ:
21+
print(
22+
f"::{level}{f' file={file.relative_to(repository_root)}' if file else ''}::{message}"
23+
)
24+
else:
25+
print(message)
26+
27+
28+
failure_counter = 0
29+
total_counter = 0
30+
for manifest_path in repository_root.rglob("manifest*.ttl"):
31+
try:
32+
(conforms, _, results_text) = validate(
33+
str(manifest_path),
34+
shacl_graph=str(shape_path),
35+
ont_graph=str(vocab_path),
36+
inference="rdfs",
37+
)
38+
except SyntaxError as e:
39+
conforms = False
40+
results_text = str(e)
41+
if not conforms:
42+
log_line(results_text, "error", manifest_path)
43+
failure_counter += 1
44+
total_counter += 1
45+
46+
log_line(
47+
f"Found {failure_counter} files with error"
48+
if failure_counter > 0
49+
else f"Validated {total_counter} files without errors",
50+
"notice",
51+
)
52+
exit(int(failure_counter > 0))

0 commit comments

Comments
 (0)