110 lines
2.5 KiB
Python
110 lines
2.5 KiB
Python
"""Standard issue body template for Forgejo issues created via Pipeline."""
|
|
|
|
from __future__ import annotations
|
|
|
|
ISSUE_TEMPLATE = """\
|
|
## Summary
|
|
Briefly describe the issue in 1 to 3 sentences.
|
|
|
|
## Problem
|
|
Explain what is wrong, missing, confusing, or broken.
|
|
|
|
## Affected area
|
|
Example:
|
|
- UI page:
|
|
- Backend service:
|
|
- API:
|
|
- Database:
|
|
- Auth:
|
|
- CI/CD:
|
|
- Docs:
|
|
|
|
## Affected files
|
|
Known or suspected files:
|
|
- `path/to/file`
|
|
- `path/to/other-file`
|
|
|
|
## Affected routes or endpoints
|
|
Known or suspected routes:
|
|
- `GET /example`
|
|
- `POST /api/example`
|
|
|
|
## Steps to reproduce
|
|
1.
|
|
2.
|
|
3.
|
|
|
|
## Expected behavior
|
|
Describe what should happen.
|
|
|
|
## Actual behavior
|
|
Describe what actually happens.
|
|
|
|
## Error output, logs, or screenshots
|
|
Paste relevant logs only. Redact secrets.
|
|
|
|
```text
|
|
Paste logs here
|
|
```\
|
|
"""
|
|
|
|
|
|
def _section(heading: str, body: str) -> str:
|
|
return f"## {heading}\n{body.strip()}"
|
|
|
|
|
|
def _code_block(content: str, lang: str = "text") -> str:
|
|
return f"```{lang}\n{content.strip()}\n```"
|
|
|
|
|
|
def render_error_report(
|
|
*,
|
|
summary: str,
|
|
problem: str,
|
|
affected_area: str | None = None,
|
|
affected_files: list[str] | None = None,
|
|
affected_routes: list[str] | None = None,
|
|
actual_behavior: str | None = None,
|
|
stack_trace: str | None = None,
|
|
reporter: str | None = None,
|
|
) -> str:
|
|
"""Render the standard template from structured error data."""
|
|
parts: list[str] = []
|
|
|
|
if reporter:
|
|
parts.append(f"_Reported by: {reporter}_\n")
|
|
|
|
parts.append(_section("Summary", summary))
|
|
|
|
parts.append(_section("Problem", problem))
|
|
|
|
area_body = affected_area.strip() if affected_area else "_Not identified._"
|
|
parts.append(_section("Affected area", area_body))
|
|
|
|
if affected_files:
|
|
files_body = "\n".join(f"- `{f}`" for f in affected_files)
|
|
else:
|
|
files_body = "_Not identified._"
|
|
parts.append(_section("Affected files", files_body))
|
|
|
|
if affected_routes:
|
|
routes_body = "\n".join(f"- `{r}`" for r in affected_routes)
|
|
else:
|
|
routes_body = "_Not identified._"
|
|
parts.append(_section("Affected routes or endpoints", routes_body))
|
|
|
|
parts.append(_section("Steps to reproduce", "_Not provided._"))
|
|
|
|
parts.append(_section("Expected behavior", "_Not provided._"))
|
|
|
|
actual = actual_behavior or problem
|
|
parts.append(_section("Actual behavior", actual))
|
|
|
|
if stack_trace:
|
|
log_body = _code_block(stack_trace)
|
|
else:
|
|
log_body = "_No output provided._"
|
|
parts.append(_section("Error output, logs, or screenshots", log_body))
|
|
|
|
return "\n\n".join(parts)
|