Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions backend/src/patchnotes/feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@
- drop a line when staff do not want it posted. A drop needs no body.
- When staff only move a line to another section, or only drop it, keep the existing body. Change the body only when they give new wording or ask for a rewrite.
- add a line only when staff asked for something that is not already there. At most 3.
- Sections, and staff win when they name one:
- new: a new player-facing thing.
- fixed: a player-facing bug that was fixed.
- adjusted: an existing feature that changed.
- technical: backend work players will not care about.
- The note is structured in four sections. Choose the section from what players care about. Staff win when they name one.
- new: a new thing players care about. It is player facing.
- fixed: a bug players will care about that was fixed.
- adjusted: an existing feature that was adjusted.
- technical: something players will not care about. Backend work about the code, and nothing player facing.
- A player-facing bug fix is fixed. A bug fix or a new change that players will not care about is technical, not fixed or new.
- For new, fixed, and adjusted, each body is one short player-facing sentence. A technical line may keep its existing wording.
- topic is one of classes, combat, magic, crafting, professions, animals, world, town, dungeons, chat.
- highlight is true only for the few lines that belong in the short summary. At most 6.
Expand Down
38 changes: 36 additions & 2 deletions backend/src/patchnotes/summarize.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@
re.IGNORECASE,
)
_NEW_WORDS = re.compile(r"\b(add|added|adds|new)\b", re.IGNORECASE)
# Backend work players will not care about. It stays technical even when the
# commit is written as a feature or a fix.
_NOT_PLAYER_FACING = re.compile(
r"(?i)("
r"\bloggers?\b|\blogging\b|\bconsole\b|"
r"\bdeprecated\b|\blisteners?\b|"
r"\bworkspace layout\b|\bserver thread\b|"
r"\bdisk reads?\b|\bblock snapshots?\b|"
r"\bmigrat(?:e|ed|ing|ion)\b|"
r"\bmaterial exclusions?\b|"
r"\bfallbacks?\b"
r")"
)
_PLAYER_FACING = re.compile(
r"(?i)\b("
r"players?|guilds?|recipes?|prices?|costs?|animals?|pets?|"
r"masks?|soups?|roasts?|furniture|discord|shops?|"
r"banners?|icons?|helmets?|skins?|spells?|"
r"characters?|ledgers?|eggs?|dough"
r")\b"
)

_SECRET = re.compile(
r"(?i)(api[_-]?key|client[_-]?secret|staff[_-]?key|password|private[_-]?key|"
Expand Down Expand Up @@ -198,14 +219,27 @@ def _split_conventional(subject: str) -> tuple[str, str]:


def _section(kind: str, text: str) -> str:
if kind in _KIND_SECTION:
return _KIND_SECTION[kind]
"""File a line by what players care about.

New is a new player-facing thing. Fixed is a player-facing bug that was
fixed. Adjusted is an existing feature that changed. Technical is backend
work players will not care about.
"""
if _NOT_PLAYER_FACING.search(text):
return "technical"
mapped = _KIND_SECTION.get(kind)
if mapped == "technical":
return "technical"
if mapped:
return mapped
if _FIX_WORDS.search(text):
return "fixed"
if _ADJUST_WORDS.search(text):
return "adjusted"
if _NEW_WORDS.search(text):
return "new"
if _PLAYER_FACING.search(text):
return "adjusted"
return "technical"


Expand Down
7 changes: 5 additions & 2 deletions backend/src/patchnotes/test_feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,11 @@ def test_omitted_lines_stay_and_a_move_can_keep_its_body(self) -> None:
def test_prompt_returns_changes_only_and_staff_sections_win(self) -> None:
self.assertNotIn("Every input id appears once", _SYSTEM)
self.assertIn("Leave every other line out", _SYSTEM)
self.assertIn("staff win when they name one", _SYSTEM)
self.assertIn("backend work players will not care about", _SYSTEM)
self.assertIn("Staff win when they name one", _SYSTEM)
self.assertIn("a new thing players care about", _SYSTEM)
self.assertIn("a bug players will care about that was fixed", _SYSTEM)
self.assertIn("an existing feature that was adjusted", _SYSTEM)
self.assertIn("nothing player facing", _SYSTEM)
self.assertNotIn("A plugin or internal change uses section technical", _SYSTEM)

def test_a_cut_off_reply_says_so(self) -> None:
Expand Down
37 changes: 37 additions & 0 deletions backend/src/patchnotes/test_summarize.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,43 @@ def test_leaves_out_pull_request_numbers(self) -> None:
)
self.assertNotIn("#38", notes.drafts[0].body)

def test_backend_work_stays_technical_even_when_written_as_a_fix(self) -> None:
notes = summarize_push(
{
"ref": "refs/heads/main",
"repository": {
"name": "TLibs",
"full_name": "TF-Minecraft/TLibs",
"default_branch": "main",
},
"commits": [
{
"id": "1" * 40,
"message": "fix: use the plugin logger for console messages",
"distinct": True,
},
{
"id": "2" * 40,
"message": "feat: migrate deprecated level-up listeners",
"distinct": True,
},
{
"id": "3" * 40,
"message": "Show the company icon under the banner for every guild",
"distinct": True,
},
],
}
)
self.assertEqual(
[(draft.section, draft.body) for draft in notes.drafts],
[
("technical", "TLibs: use the plugin logger for console messages"),
("technical", "TLibs: migrate deprecated level-up listeners"),
("adjusted", "TLibs: Show the company icon under the banner for every guild"),
],
)

def test_strips_coordinates_and_keeps_the_fix(self) -> None:
notes = summarize_push(_push("fix: Fixed a chest at 1204, 64, -880"))
self.assertEqual(len(notes.drafts), 1)
Expand Down