merge: reconcile the feature-container convention with the depends validator
This commit is contained in:
@@ -140,13 +140,20 @@ EXCLUSIVE_NS = ("type/", "severity/")
|
||||
REQUIRED_SECTIONS = ["## Summary", "## Spec"]
|
||||
AC_SECTION = "## Acceptance criteria"
|
||||
DEPENDS_SECTION = "## Depends on"
|
||||
ISSUES_SECTION = "## Issues"
|
||||
# Both sections name what an issue depends on, so both are edge sources and
|
||||
# both point the same way. In a `type/feature` that reads container -> child:
|
||||
# "the container is closed when its children are closed" IS a dependency.
|
||||
# "a child belongs to a feature" is membership, and membership has no place in
|
||||
# a dependency graph — which is why a child never names its container back.
|
||||
DEP_SECTIONS = (DEPENDS_SECTION, ISSUES_SECTION)
|
||||
# Per-type sections from the templates — absence is a warning, not a stop.
|
||||
EXPECTED_SECTIONS = {
|
||||
"bug": ["## Steps to reproduce", "## Expected", "## Actual", "## Environment"],
|
||||
"task": ["## Motivation"],
|
||||
"refactor": ["## Motivation", "## Invariants"],
|
||||
"test": ["## Motivation", "## Test cases"],
|
||||
"feature": ["## Motivation", "## Issues"],
|
||||
"feature": ["## Motivation", ISSUES_SECTION],
|
||||
"draft": ["## Notes"],
|
||||
}
|
||||
|
||||
@@ -327,24 +334,37 @@ def section_body(body, header):
|
||||
return "\n".join(out).strip()
|
||||
|
||||
|
||||
def body_dep_refs(body):
|
||||
"""Tokens referenced from `## Depends on` / `## Issues` only — never from
|
||||
prose, or a graph walk would drag in half the backlog. Returns whatever was
|
||||
written there (slugs, and `#N` on issues that came from a tracker)."""
|
||||
out, active = [], False
|
||||
def body_dep_ref_sections(body):
|
||||
"""[(section, ref)] for every reference under one of DEP_SECTIONS — never
|
||||
from prose, or a graph walk would drag in half the backlog. Refs are
|
||||
whatever was written there (slugs, and `#N` on issues that came from a
|
||||
tracker), deduplicated on first sight.
|
||||
|
||||
The section is carried out with the ref so a caller can name the one the
|
||||
reader actually has in front of them: a container's children come from
|
||||
`## Issues`, and pointing at `## Depends on` would name a section that is
|
||||
not in the file."""
|
||||
out, seen, section = [], set(), ""
|
||||
for line in (body or "").splitlines():
|
||||
if line.startswith("## "):
|
||||
active = line.strip() in (DEPENDS_SECTION, "## Issues")
|
||||
head = line.strip()
|
||||
section = head if head in DEP_SECTIONS else ""
|
||||
continue
|
||||
if not active:
|
||||
if not section:
|
||||
continue
|
||||
for tok in re.findall(r'#(\d+)|\b([a-z0-9]+(?:-[a-z0-9]+)+)\b', line):
|
||||
ref = ("#" + tok[0]) if tok[0] else tok[1]
|
||||
if ref not in out:
|
||||
out.append(ref)
|
||||
if ref not in seen:
|
||||
seen.add(ref)
|
||||
out.append((section, ref))
|
||||
return out
|
||||
|
||||
|
||||
def body_dep_refs(body):
|
||||
"""Just the refs, in order of first appearance."""
|
||||
return [ref for _, ref in body_dep_ref_sections(body)]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# validation
|
||||
# --------------------------------------------------------------------------
|
||||
@@ -402,12 +422,13 @@ def validate(issue, known_ids=None):
|
||||
warn.append("depends on %r, which is not in the store" % d)
|
||||
|
||||
# `depends:` is the machine-readable graph; the body section is prose for
|
||||
# humans. They drift silently unless something says so.
|
||||
# humans. They drift silently unless something says so. Name the section
|
||||
# the reference actually came from — for a container that is `## Issues`.
|
||||
listed = set(issue.depends)
|
||||
for ref in body_dep_refs(issue.body):
|
||||
for section, ref in body_dep_ref_sections(issue.body):
|
||||
if not ref.startswith("#") and ref not in listed:
|
||||
warn.append("%s mentions %r but `depends:` does not list it"
|
||||
% (DEPENDS_SECTION, ref))
|
||||
% (section, ref))
|
||||
|
||||
return err, warn
|
||||
|
||||
|
||||
Reference in New Issue
Block a user