towerops/lib/towerops_web/changelog_parser.ex
Graham McIntie 9e7ee5099d refactor: fix all credo strict issues, format all code, fix broken routes
- Fix broken route paths in dashboard (/discovery, /subscribers/trace, /config-changes)
- Fix insights empty state settings link (org-scoped route)
- Add underscores to all 86400 literals across 6 files
- Alphabetize aliases in search.ex and agent_channel.ex
- Extract changelog parser helper to reduce nesting
- Extract dashboard impact calculation to reduce nesting
- Refactor agent_channel config change detection (pattern match, extract function)
- Combine double Enum.reject into single call in trace.ex
- Fix line length in trace.ex search query
- Replace length/1 > 0 with != [] in trace_live
- Run mix format on all files
2026-02-13 19:34:40 -06:00

45 lines
1.5 KiB
Elixir

defmodule ToweropsWeb.ChangelogParser do
@moduledoc "Parses priv/static/changelog.txt into structured entries."
@doc "Returns a list of %{date: Date.t(), title: String.t(), items: [String.t()]}"
def parse do
path = Application.app_dir(:towerops, "priv/static/changelog.txt")
case File.read(path) do
{:ok, content} -> parse_content(content)
{:error, _} -> []
end
end
defp parse_content(content) do
content
|> String.split("\n")
|> Enum.reduce([], fn line, acc ->
cond do
# Date header with title: "2026-02-13 — Title"
Regex.match?(~r/^\d{4}-\d{2}-\d{2}\s*[—–-]\s*.+/, line) ->
[date_str, title] = String.split(line, ~r/\s*[—–-]\s*/, parts: 2)
entry = %{date: Date.from_iso8601!(String.trim(date_str)), title: String.trim(title), items: []}
[entry | acc]
# Date header without title: "2026-02-13"
Regex.match?(~r/^\d{4}-\d{2}-\d{2}\s*$/, line) ->
date = Date.from_iso8601!(String.trim(line))
entry = %{date: date, title: nil, items: []}
[entry | acc]
# Bullet point
String.starts_with?(String.trim(line), "* ") ->
add_item_to_current(acc, line |> String.trim() |> String.trim_leading("* "))
true ->
acc
end
end)
|> Enum.reverse()
end
defp add_item_to_current([current | rest], item), do: [%{current | items: current.items ++ [item]} | rest]
defp add_item_to_current([], _item), do: []
end