From 6db903c612dbbddfa3b71dc778627124de152224 Mon Sep 17 00:00:00 2001 From: Filipe Moreira <108258235+lippdev@users.noreply.github.com> Date: Mon, 19 Oct 2026 18:41:29 +0200 Subject: [PATCH 1/2] feat: show the update notice's highlight in Portuguese, and in any language with a changelog Since 1.5.0-beta.6 the release body is English only, so everyone, Portuguese users included, read the update notice in English. The release workflow now appends one hidden line per translated changelog (CHANGELOG.md for pt-BR, any CHANGELOG..md for another language), after the notes so older clients still show the English item. ReleaseNotes.FirstLine prefers the summary for the interface language and strips Markdown links. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 31 +++++++++++--- src/ConsoleMode/Services/ReleaseNotes.cs | 39 +++++++++++++++-- tests/ConsoleMode.Tests/ReleaseNotesTests.cs | 45 ++++++++++++++++++++ 3 files changed, 107 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c8a8c31..5d00b68 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,7 +63,7 @@ jobs: "prerelease=$($v.Contains('-').ToString().ToLower())" >> $env:GITHUB_OUTPUT "publish=$($publish.ToString().ToLower())" >> $env:GITHUB_OUTPUT - - name: Prepare release notes (English, with a link to the Portuguese changelog) + - name: Prepare release notes (English, a link to the Portuguese changelog, a summary per translated changelog) if: steps.version.outputs.publish == 'true' shell: pwsh env: @@ -79,10 +79,29 @@ jobs: return $notes } # Both changelogs must have the section; the Portuguese one is linked, not pasted. - $null = Get-Notes "CHANGELOG.md" + $pt = Get-Notes "CHANGELOG.md" $en = Get-Notes "CHANGELOG.en-US.md" - # English only, no language headings: ReleaseNotes.cs shows the first item to every - # language. A "(#NN)" at the end of an item becomes a link to that PR on GitHub. + # One hidden "" line per translated changelog (CHANGELOG.md is + # pt-BR, any CHANGELOG..md another language): the update notice shows it instead + # of the English first item (ReleaseNotes.cs). They go at the very end of the body, so + # clients up to 1.6.x, which show the first line they find, keep showing the English one. + function Get-FirstItem([string]$notes) { + $item = $notes -split "\r?\n" | Where-Object { $_ -match '^\s*[-*]\s+\S' } | Select-Object -First 1 + if (-not $item) { return $null } + return ($item -replace '^\s*[-*]\s+', '' -replace '-->', '').Trim() + } + $summaries = @() + $ptItem = Get-FirstItem $pt + if ($ptItem) { $summaries += "" } + foreach ($file in Get-ChildItem -Name -Filter "CHANGELOG.*.md" | Where-Object { $_ -ne "CHANGELOG.en-US.md" } | Sort-Object) { + $code = $file -replace '^CHANGELOG\.|\.md$', '' + # Optional: a translated changelog without this version's section is skipped, not fatal. + $notes = try { Get-Notes $file } catch { Write-Host "$file sem a seção $($env:VERSION); sem resumo em $code."; $null } + $item = if ($notes) { Get-FirstItem $notes } + if ($item) { $summaries += "" } + } + # English, no language headings: ReleaseNotes.cs shows its first item to every + # language without a summary. A "(#NN)" at the end of an item becomes a link to that PR on GitHub. $tag = "v$($env:VERSION)" $releaseNotes = @( $en @@ -96,7 +115,9 @@ jobs: "---" "" "🇧🇷 Notas em português: [CHANGELOG.md](https://github.com/lippdev/consolemode/blob/$tag/CHANGELOG.md)" - ) -join "`n" + ) + if ($summaries.Count -gt 0) { $releaseNotes += @("") + $summaries } + $releaseNotes = $releaseNotes -join "`n" Set-Content -LiteralPath "release-notes.md" -Value $releaseNotes -Encoding utf8 - name: Run tests diff --git a/src/ConsoleMode/Services/ReleaseNotes.cs b/src/ConsoleMode/Services/ReleaseNotes.cs index 5608351..f66ccc7 100644 --- a/src/ConsoleMode/Services/ReleaseNotes.cs +++ b/src/ConsoleMode/Services/ReleaseNotes.cs @@ -1,15 +1,24 @@ +using System.Text.RegularExpressions; + namespace ConsoleMode.Services; /// /// Reads the GitHub release body written by .github/workflows/release.yml. /// Since 1.5.0 the body has one section per language, each opened by a fixed /// "## …" heading; older releases are pt-BR only, with no language headings. +/// Since 1.7.0 the body ends with one hidden summary per translated changelog +/// (), which wins over the English notes. /// public static class ReleaseNotes { public const string PortugueseHeading = "## Português (Brasil)"; public const string EnglishHeading = "## English (US)"; + /// "<!-- summary pt-BR: first item -->": an HTML comment, so GitHub doesn't show it. + public const string SummaryPrefix = "", StringComparison.Ordinal)) continue; + var line = Clean(trimmed[prefix.Length..^3]); + if (line.Length > 0) return line; + } + return null; + } + + /// Plain text for the notice: no list marker, bold or link syntax, at most 140 characters. + private static string Clean(string text) + { + var line = MarkdownLink.Replace(text.Trim().TrimStart('-', '*', ' ').Replace("**", ""), "$1").Trim(); + return line.Length > 140 ? line[..140] + "…" : line; + } + private static bool IsHeading(string line, string heading) => string.Equals(line.Trim().TrimStart(''), heading, StringComparison.Ordinal); } diff --git a/tests/ConsoleMode.Tests/ReleaseNotesTests.cs b/tests/ConsoleMode.Tests/ReleaseNotesTests.cs index 4030ab0..9d156d0 100644 --- a/tests/ConsoleMode.Tests/ReleaseNotesTests.cs +++ b/tests/ConsoleMode.Tests/ReleaseNotesTests.cs @@ -80,6 +80,51 @@ public void FirstLine_EnglishOnlyBodyIsSharedByEveryLanguage() Assert.Equal("Session menu over the game. (#46)", ReleaseNotes.FirstLine(englishOnly, LocalizationService.SpanishSpain)); } + private const string WithSummaries = """ + ### What's new + - **Minimize to the system tray:** a new option in Settings. (#150) + + --- + + 🇧🇷 Notas em português: [CHANGELOG.md](https://example.com/CHANGELOG.md) + + + """; + + [Fact] + public void FirstLine_HiddenSummaryWinsForItsLanguage() + { + Assert.Equal("Minimizar para a bandeja: traduzida por u/Skinner99. (#150)", + ReleaseNotes.FirstLine(WithSummaries, LocalizationService.PortugueseBrazil)); + Assert.Equal("Minimizar para a bandeja: traduzida por u/Skinner99. (#150)", + ReleaseNotes.FirstLine(WithSummaries.Replace("\n", "\r\n"), LocalizationService.PortugueseBrazil)); + } + + [Fact] + public void FirstLine_LanguagesWithoutASummaryReadTheEnglishNotes() + { + Assert.Equal("Minimize to the system tray: a new option in Settings. (#150)", + ReleaseNotes.FirstLine(WithSummaries, LocalizationService.EnglishUnitedStates)); + Assert.Equal("Minimize to the system tray: a new option in Settings. (#150)", + ReleaseNotes.FirstLine(WithSummaries, LocalizationService.GermanGermany)); + } + + [Fact] + public void FirstLine_EmptyOrUnclosedSummaryFallsBackToTheNotes() + { + Assert.Equal("Item.", ReleaseNotes.FirstLine("- Item.\n", LocalizationService.PortugueseBrazil)); + Assert.Equal("Item.", ReleaseNotes.FirstLine("- Item.\n