спринт: шапка SPRINT.md — мета-блоком, как у задачи
Последнее место, где поля писались одной строкой через ·: цель, дата начала и слаг спринта. После переезда меты задачи в блок эта строка осталась единственным исключением, а объяснять два формата дороже, чем иметь один. Старая шапка читается по-прежнему — GOAL_LINE берёт строку и с ведущим «- », SPRINT_SLUG_LINE и раньше искала по всей строке. Починки для неё нет и не нужно: SPRINT.md переписывается целиком на sprint start и очищается на sprint close, так что старая форма живёт не дольше идущего спринта. Форма заодно описана в task-format.md — до сих пор она жила только в коде, и человек, читавший документ формата, о ней не узнавал. Проверено на временном проекте: start → take → check → подсунутая старая шапка → drop → close; цель и слаг читаются в обеих формах. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -172,6 +172,12 @@
|
|||||||
| `SPRINT.md` | какая цель и какой набор под неё | одна: «Набор» |
|
| `SPRINT.md` | какая цель и какой набор под неё | одна: «Набор» |
|
||||||
| `REJECTED.md` | что ушло без реализации и почему | — |
|
| `REJECTED.md` | что ушло без реализации и почему | — |
|
||||||
|
|
||||||
|
Шапку `SPRINT.md` пишет `sprint start` — **тем же мета-блоком, что у задачи**:
|
||||||
|
поле на строку, `- **Цель:** [Заголовок](items/slug.md)`, `- **Начат:**` датой,
|
||||||
|
`- **Спринт:**` слагом, которым метится урожай. Прежняя форма (три поля одной
|
||||||
|
строкой через `·`) читается по-прежнему и уходит сама: файл переписывается на
|
||||||
|
следующем `sprint start` и очищается на `sprint close`.
|
||||||
|
|
||||||
Секции — **единственные заголовки `##` в индексе**: любой другой `##` в
|
Секции — **единственные заголовки `##` в индексе**: любой другой `##` в
|
||||||
преамбуле проверка сочтёт секцией. Внутри секции беклога порядок значения не
|
преамбуле проверка сочтёт секцией. Внутри секции беклога порядок значения не
|
||||||
имеет — порядка в беклоге нет вовсе.
|
имеет — порядка в беклоге нет вовсе.
|
||||||
|
|||||||
@@ -161,7 +161,9 @@ SECTION = re.compile(r"^##\s+(.+?)\s*$")
|
|||||||
TYPE_PREFIX = re.compile(r"^\[(.+?)\]\s*(.*)$")
|
TYPE_PREFIX = re.compile(r"^\[(.+?)\]\s*(.*)$")
|
||||||
SLUG_RE = re.compile(r"[a-z0-9]+(?:-[a-z0-9]+)*")
|
SLUG_RE = re.compile(r"[a-z0-9]+(?:-[a-z0-9]+)*")
|
||||||
SLUG = re.compile(SLUG_RE.pattern + r"\.md")
|
SLUG = re.compile(SLUG_RE.pattern + r"\.md")
|
||||||
GOAL_LINE = re.compile(r"^\*\*(?:Цель|Goal):\*\*\s*\[(.+?)\]\((.+?\.md)\)")
|
GOAL_LINE = re.compile(r"^(?:-\s+)?\*\*(?:Цель|Goal):\*\*\s*\[(.+?)\]\((.+?\.md)\)")
|
||||||
|
# `search`, а не `match`: строка меты идёт пунктом списка, а прежняя форма —
|
||||||
|
# третьим полем строки через `·`. Обе читаются, пишется новая.
|
||||||
SPRINT_SLUG_LINE = re.compile(r"\*\*(?:Спринт|Sprint):\*\*\s*`?([a-z0-9][a-z0-9.-]*)`?")
|
SPRINT_SLUG_LINE = re.compile(r"\*\*(?:Спринт|Sprint):\*\*\s*`?([a-z0-9][a-z0-9.-]*)`?")
|
||||||
DATE_RE = re.compile(r"\d{4}-\d{2}-\d{2}")
|
DATE_RE = re.compile(r"\d{4}-\d{2}-\d{2}")
|
||||||
BULLET = re.compile(r"^[-*]\s+(.*)$")
|
BULLET = re.compile(r"^[-*]\s+(.*)$")
|
||||||
@@ -651,10 +653,18 @@ def sprint_slug(lay: Layout) -> str:
|
|||||||
|
|
||||||
def sprint_header(lay: Layout, goal_slug: str, goal_title: str,
|
def sprint_header(lay: Layout, goal_slug: str, goal_title: str,
|
||||||
date: str, slug: str) -> list[str]:
|
date: str, slug: str) -> list[str]:
|
||||||
|
"""Шапка спринта — мета-блок той же формы, что у задачи: поле на строку.
|
||||||
|
|
||||||
|
Прежняя форма (все три поля одной строкой через `·`) читается по-прежнему
|
||||||
|
— обе регулярки её берут, — но чинить её нечем и не нужно: `SPRINT.md`
|
||||||
|
переписывается целиком на `sprint start` и очищается на `sprint close`,
|
||||||
|
так что старая шапка живёт не дольше идущего спринта.
|
||||||
|
"""
|
||||||
link = f"{lay.cfg['items']}/{goal_slug}.md"
|
link = f"{lay.cfg['items']}/{goal_slug}.md"
|
||||||
return ["# Спринт", "",
|
return ["# Спринт", "",
|
||||||
f"**Цель:** [{goal_title}]({link}) · **Начат:** {date}"
|
f"- **Цель:** [{goal_title}]({link})",
|
||||||
f" · **Спринт:** `{slug}`", "",
|
f"- **Начат:** {date}",
|
||||||
|
f"- **Спринт:** `{slug}`", "",
|
||||||
f"Урожай спринта поднимается `tasks.py list --tag {SPRINT_TAG}{slug}`"
|
f"Урожай спринта поднимается `tasks.py list --tag {SPRINT_TAG}{slug}`"
|
||||||
" — это первая порция переоценки на сессии.", ""]
|
" — это первая порция переоценки на сессии.", ""]
|
||||||
|
|
||||||
@@ -837,7 +847,7 @@ def check(lay: Layout, fix: bool = False) -> int:
|
|||||||
if not goal_of_sprint and entries["sprint"]:
|
if not goal_of_sprint and entries["sprint"]:
|
||||||
errors.append(f"{label['sprint']}: набор есть, а цель не названа")
|
errors.append(f"{label['sprint']}: набор есть, а цель не названа")
|
||||||
if goal_of_sprint and not sprint_slug(lay):
|
if goal_of_sprint and not sprint_slug(lay):
|
||||||
errors.append(f"{label['sprint']}: у спринта нет слага (**Спринт:** `…`) —"
|
errors.append(f"{label['sprint']}: у спринта нет слага (- **Спринт:** `…`) —"
|
||||||
f" урожай не отобрать; перезапусти `sprint start`")
|
f" урожай не отобрать; перезапусти `sprint start`")
|
||||||
|
|
||||||
rejected = lay.index("rejected")
|
rejected = lay.index("rejected")
|
||||||
|
|||||||
Reference in New Issue
Block a user