Skip to content

Commit 29f2ccd

Browse files
committed
chore: roadmap validator draft 2
1 parent c72dd2d commit 29f2ccd

File tree

7 files changed

+62
-89
lines changed

7 files changed

+62
-89
lines changed
Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11
name: Roadmap Validator
22

33
on:
4-
pull_request:
5-
paths:
6-
- 'content/qa/**'
7-
- 'tools/roadmap_validator/validate.py'
8-
- 'tools/roadmap_validator/**'
9-
- '.github/workflows/roadmap-validator.yml'
4+
workflow_dispatch:
5+
inputs:
6+
paths:
7+
description: 'Space-separated paths or directories to validate'
8+
required: false
9+
default: ''
1010
push:
1111
branches:
1212
- main
13+
- chore/roadmap-validator
1314
paths:
15+
- 'content/acz/**'
16+
- 'content/dst/**'
1417
- 'content/qa/**'
15-
- 'tools/roadmap_validator/validate.py'
18+
- 'content/nes/**'
19+
- 'content/nim/**'
20+
- 'content/p2p/**'
21+
- 'content/rfc/**'
22+
- 'content/sc/**'
23+
- 'content/sec/**'
24+
- 'content/tke/**'
25+
- 'content/web/**'
1626
- 'tools/roadmap_validator/**'
1727
- '.github/workflows/roadmap-validator.yml'
1828

1929
jobs:
2030
validate:
2131
runs-on: ubuntu-latest
22-
env:
23-
TARGET_DIRECTORIES: "content/qa"
2432
steps:
2533
- name: Checkout
2634
uses: actions/checkout@v4
@@ -35,33 +43,28 @@ jobs:
3543
- name: Install dependencies
3644
run: pip install --disable-pip-version-check --no-cache-dir pyyaml
3745

46+
- name: Detect changed markdown files
47+
if: ${{ github.event_name != 'workflow_dispatch' }}
48+
id: changed-files
49+
uses: tj-actions/changed-files@v42
50+
with:
51+
files: |
52+
**/*.md
53+
3854
- name: Run roadmap validator
3955
run: |
4056
set -eo pipefail
41-
BASE_SHA="${{ github.event.pull_request.base.sha || github.event.before }}"
42-
if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
43-
CHANGED_FILES=$(git ls-files)
44-
else
45-
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT "$BASE_SHA" "$GITHUB_SHA")
46-
fi
4757
48-
TARGET_FILES=""
49-
for file in $CHANGED_FILES; do
50-
for dir in $TARGET_DIRECTORIES; do
51-
case "$file" in
52-
$dir/*.md)
53-
if [ -f "$file" ]; then
54-
TARGET_FILES="$TARGET_FILES $file"
55-
fi
56-
;;
57-
esac
58-
done
59-
done
60-
61-
if [ -z "$TARGET_FILES" ]; then
62-
echo "No roadmap markdown changes detected."
63-
exit 0
58+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
59+
TARGETS="${{ github.event.inputs.paths }}"
60+
else
61+
TARGETS="${{ steps.changed-files.outputs.all_changed_files }}"
62+
if [ -z "$TARGETS" ]; then
63+
echo "No roadmap markdown changes detected."
64+
exit 0
65+
fi
6466
fi
6567
66-
echo "Validating files:$TARGET_FILES"
67-
python tools/roadmap_validator/validate.py $TARGET_FILES
68+
echo "Validating targets:"
69+
printf '%s\n' $TARGETS
70+
python tools/roadmap_validator/validate.py $TARGETS

tools/roadmap_validator/constants.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,3 @@
6868
)
6969

7070
DEFAULT_SKIP_FILENAMES = {"index.md"}
71-
72-
__all__ = [
73-
"REQUIRED_FRONT_MATTER_KEYS",
74-
"REQUIRED_TASK_FIELDS",
75-
"METADATA_ALIAS_MAP",
76-
"DATE_RE",
77-
"TODO_RE",
78-
"TASK_HEADING_RE",
79-
"META_LINE_RE",
80-
"VAGUE_KEYWORDS",
81-
"TANGIBLE_KEYWORDS",
82-
"DEFAULT_SKIP_FILENAMES",
83-
]

tools/roadmap_validator/identity.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
import re
44
from dataclasses import dataclass
55
from pathlib import Path
6-
from typing import Dict, List, Optional
7-
8-
from .paths import CONTENT_ROOT, should_skip
6+
from typing import Dict, List, Optional, Tuple
7+
from paths import CONTENT_ROOT, should_skip
98

109
IDENTIFIER_PATTERN = re.compile(r"^`([^`]+)`\s*$")
1110
FILENAME_PATTERN = re.compile(r"^(?P<quarter>\d{4}q[1-4])-(?P<slug>.+)$")
@@ -22,33 +21,40 @@ class CommitmentIdentity:
2221
expected_base: str
2322

2423

25-
def derive_identity(path: Path) -> Optional[CommitmentIdentity]:
24+
def derive_identity(path: Path) -> Tuple[Optional[CommitmentIdentity], List[str]]:
2625
"""Infer roadmap identity metadata from the file path."""
26+
issues: List[str] = []
2727
try:
2828
relative = path.resolve().relative_to(CONTENT_ROOT)
2929
except ValueError:
30-
return None
30+
return None, issues
3131
if len(relative.parts) < 3 or should_skip(path):
32-
return None
32+
return None, issues
3333

3434
unit, area = relative.parts[0], relative.parts[1]
3535
match = FILENAME_PATTERN.match(path.stem)
3636
if not match:
37-
return None
37+
issues.append(
38+
f"{path}: filename should follow `<year>q<quarter>-<slug>.md` (found `{path.name}`)"
39+
)
40+
return None, issues
3841

3942
quarter = match.group("quarter")
4043
slug = match.group("slug")
4144
expected_base = f"vac:{unit}:{area}:{quarter}-{slug}"
4245
expected_tags = [quarter, unit, area]
4346
expected_identifier = expected_base
44-
return CommitmentIdentity(
47+
return (
48+
CommitmentIdentity(
4549
unit=unit,
4650
quarter=quarter,
4751
area=area,
4852
slug=slug,
4953
expected_tags=expected_tags,
5054
expected_identifier=expected_identifier,
5155
expected_base=expected_base,
56+
),
57+
issues,
5258
)
5359

5460

@@ -96,6 +102,3 @@ def validate_identity(
96102
)
97103

98104
return issues
99-
100-
101-
__all__ = ["CommitmentIdentity", "derive_identity", "validate_identity"]

tools/roadmap_validator/paths.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from pathlib import Path
66
from typing import Iterable, List, Optional
77

8-
from .constants import DEFAULT_SKIP_FILENAMES
8+
from constants import DEFAULT_SKIP_FILENAMES
99

1010
REPO_ROOT = Path(__file__).resolve().parents[2]
1111
CONTENT_ROOT = REPO_ROOT / "content"
@@ -63,11 +63,3 @@ def resolve_targets(targets: Iterable[str]) -> List[Path]:
6363
else:
6464
sys.stderr.write(f"Warning: skipping non-markdown path {raw_target!r}\n")
6565
return md_files
66-
67-
68-
__all__ = [
69-
"CONTENT_ROOT",
70-
"REPO_ROOT",
71-
"should_skip",
72-
"resolve_targets",
73-
]

tools/roadmap_validator/tasks.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
from dataclasses import dataclass, field
44
from typing import Dict, List, Optional, Tuple
5-
6-
from .constants import (
5+
from constants import (
76
DATE_RE,
87
META_LINE_RE,
98
METADATA_ALIAS_MAP,
@@ -193,6 +192,3 @@ def flush_current() -> None:
193192

194193
flush_current()
195194
return tasks
196-
197-
198-
__all__ = ["TaskIssue", "TaskReport", "parse_tasks"]

tools/roadmap_validator/validate.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,11 @@
55
import os
66
import shlex
77
import sys
8-
from pathlib import Path
98
from typing import Iterable, List, Optional
9+
from paths import resolve_targets
10+
from validator import validate_file
1011

11-
if __package__ is None or __package__ == "":
12-
sys.path.append(str(Path(__file__).resolve().parent.parent.parent))
13-
from tools.roadmap_validator.paths import resolve_targets
14-
from tools.roadmap_validator.validator import validate_file
15-
else:
16-
from .paths import resolve_targets
17-
from .validator import validate_file
18-
19-
DEFAULT_TARGETS = "qa"
12+
DEFAULT_TARGETS = "acz dst qa nes nim p2p rfc sc sec tke web"
2013

2114

2215
def run_validator(targets: Iterable[str]) -> int:

tools/roadmap_validator/validator.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
import yaml
77

8-
from .constants import REQUIRED_FRONT_MATTER_KEYS
9-
from .identity import derive_identity, validate_identity
10-
from .paths import should_skip
11-
from .tasks import TaskReport, parse_tasks
8+
from constants import REQUIRED_FRONT_MATTER_KEYS
9+
from identity import derive_identity, validate_identity
10+
from paths import should_skip
11+
from tasks import TaskReport, parse_tasks
1212

1313

1414
def parse_front_matter(lines: List[str]) -> Tuple[dict, int]:
@@ -69,7 +69,9 @@ def validate_file(path: Path) -> List[str]:
6969
f"{path}: {message}" for message in validate_front_matter(front_matter)
7070
)
7171

72-
identity = derive_identity(path)
72+
identity, identity_issues = derive_identity(path)
73+
issues.extend(identity_issues)
74+
7375
expected_base = None
7476
if identity:
7577
issues.extend(
@@ -92,6 +94,3 @@ def validate_file(path: Path) -> List[str]:
9294
for issue in task.issues:
9395
issues.append(f"{path}:{issue.line}: Task `{task.name}` {issue.message}")
9496
return issues
95-
96-
97-
__all__ = ["validate_file"]

0 commit comments

Comments
 (0)