diff --git a/.azure/pipelines/build-whiteboard.yaml b/.azure/pipelines/build-whiteboard.yaml index 3dd338a..e5f164e 100644 --- a/.azure/pipelines/build-whiteboard.yaml +++ b/.azure/pipelines/build-whiteboard.yaml @@ -68,6 +68,11 @@ trigger: # that is byte-identical to the one before it. - installer/winget - scripts/build-release-manifests.ps1 + # The notes for a release that already exists, and the script that reads them. A + # wording fix should not cut a pre-release; the notes for a version that has not + # shipped arrive with the VersionPrefix bump, which does trigger one. + - CHANGELOG.md + - scripts/release-notes.ps1 # The same reasoning, one file rather than the folder: the rest of installer/msix is # the package manifest and its assets, which do go into a build. The listing text is # a record of what was typed into Partner Center by hand and is read by nothing. @@ -361,6 +366,25 @@ stages: parameters: channel: stable + # The release body used to be the one line "SQLBI Whiteboard .", which + # told a reader nothing, and addChangeLog would have replaced it with a list of + # commit subjects, which tells them too much of the wrong kind. Both come from + # CHANGELOG.md instead, so the release page and the What's new page on the site + # carry the same words and those words are written once. + # + # This fails the stage when the version has no entry. That is the point: the + # release has not been created yet when it runs, so an unwritten changelog stops + # the release rather than being noticed after it is public. + - task: PowerShell@2 + displayName: 'Take the release notes from CHANGELOG.md' + inputs: + filePath: 'scripts/release-notes.ps1' + arguments: >- + -Mode Markdown + -Version $(AppSemVer) + -OutFile "$(Build.ArtifactStagingDirectory)/release-notes.md" + pwsh: true + - task: GitHubRelease@1 displayName: 'Create the GitHub release' inputs: @@ -373,9 +397,8 @@ stages: # same version twice: bump VersionPrefix instead. tag: 'v$(AppSemVer)' title: 'SQLBI Whiteboard $(AppSemVer)' - releaseNotesSource: inline - releaseNotes: | - SQLBI Whiteboard $(AppSemVer). + releaseNotesSource: filePath + releaseNotesFilePath: '$(Build.ArtifactStagingDirectory)/release-notes.md' assets: '$(Build.ArtifactStagingDirectory)/release/*' isPreRelease: false addChangeLog: false diff --git a/.github/workflows/publish-site.yml b/.github/workflows/publish-site.yml index a38432f..5b6fc4f 100644 --- a/.github/workflows/publish-site.yml +++ b/.github/workflows/publish-site.yml @@ -25,8 +25,10 @@ on: branches: [main] paths: - 'site/**' + - 'CHANGELOG.md' - 'scripts/build-release-manifests.ps1' - 'scripts/verify-published-site.ps1' + - 'scripts/release-notes.ps1' - '.github/workflows/publish-site.yml' # A release changes what the manifests say without changing anything in site/, so it has # to redeploy the page as well. This is what keeps the download links current. @@ -68,6 +70,25 @@ jobs: GH_TOKEN: ${{ github.token }} EXPECT_TAG: ${{ github.event.release.tag_name }} + # A released version with no entry in CHANGELOG.md would publish a What's new page + # that does not mention the version people are being offered. Checked here as well as + # on the pull request that bumps VersionPrefix, because a release does not have to + # have come from one. Pre-releases are exempt: Dev builds come from every merge and + # are deliberately not in the changelog. + - name: Check this release has notes + if: github.event_name == 'release' && github.event.release.prerelease == false + shell: pwsh + run: ./scripts/release-notes.ps1 -Mode Verify -Version "$env:RELEASE_TAG" + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} + + # Written into the page rather than fetched from the API by the page itself: the + # notes are then in the HTML that ships, so they are readable without scripting and + # findable by a search engine. + - name: Write the release notes into the page + shell: pwsh + run: ./scripts/release-notes.ps1 -Mode Html + - uses: actions/configure-pages@v5 - uses: actions/upload-pages-artifact@v3 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 76eb5a0..4e58970 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -56,6 +56,42 @@ jobs: echo "-> nothing to build: only the site, docs, vscode extension or markdown changed" fi + # Release notes are written while the change is fresh, in the pull request that bumps the + # version, rather than remembered under pressure once the release is already public. The + # release itself is checked again in publish-site.yml. + notes: + name: Release notes + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Check the version bump brings its notes + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + Set-StrictMode -Version Latest + + $base = "origin/$env:BASE_REF" + function Get-VersionPrefix([string]$text) { + if ($text -match '(.*?)') { return $Matches[1].Trim() } + return '' + } + + $before = Get-VersionPrefix (git show "${base}:Directory.Build.props" | Out-String) + $after = Get-VersionPrefix (Get-Content Directory.Build.props -Raw) + + if ($before -eq $after) { + Write-Host "VersionPrefix is unchanged at $after, so no new notes are due." + return + } + + Write-Host "VersionPrefix goes $before -> $after." + ./scripts/release-notes.ps1 -Mode Verify -Version $after + env: + BASE_REF: ${{ github.base_ref }} + build: name: Build and test needs: changes diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..961e575 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,111 @@ +# What's new + +What a released version gives you that the one before it did not, written for the person +deciding whether to upgrade rather than for the person who wrote the code. + +This file is the source for both the [What's new page](https://whiteboard.sqlbi.com/changelog.html) +and the notes on each GitHub release, so it is written once and read in both places. Only +released versions appear. Pre-release **Dev** builds are published continuously from `main` +and are not listed here; their commit history is on GitHub. Nor are the releases before +1.0.0, which built the application up to its first stable version and are on +[GitHub Releases](https://github.com/sql-bi/SQLBI-Whiteboard/releases) with their own notes. + +**Adding an entry.** One `## - ` heading, then one `###` heading per thing a +person would notice, each with a sentence or two saying what changed and what it is for. A +release with nothing worth noticing still needs an entry — say that it is a fix and what +broke. The heading is parsed by `scripts/release-notes.ps1`, so keep its shape; the prose +under it is ordinary Markdown, and the renderer handles paragraphs, lists, links, `code` +and **bold**. + +## 1.2.2 - 2 September 2026 + +### The Eraser, for a pen that has none +Not every pen has an eraser on its back end, and until now those pens could not reach the +Eraser tool at all — it appears on the toolbar only when finger or mouse drawing puts it +there. **Preferences → Toolbar → Always show the Eraser** keeps it there for the pen too. +It is off by default, so nothing changes for a pen that already erases. In the compact +toolbar layouts the Eraser joins the row of tools rather than taking a row of its own. + +### Preferences you can read +Every setting is now one line: a title and a single sentence saying what it is for. The +defaults, the reasoning and the consequences moved behind a chevron, so a category can be +skimmed instead of read. Searching marks what it matched, and marks the chevron when the +match is in the text behind it, and the search box has a button to clear it. + +## 1.2.1 - 31 August 2026 + +### Mouse drawing offers itself +With Mouse drawing off, picking a tool from the toolbar with the mouse now offers to turn +it on. Reaching for the palette with a mouse is the one moment the application can be sure +the question is worth asking — a pen user reaches for it with the pen. The offer appears +once a session, and once declined for good it does not come back. + +## 1.2.0 - 30 August 2026 + +### The mouse can draw +The left mouse button now does what the selected tool does: ink, erase, select, pan, or the +laser. It defaults to on when Windows reports neither a pen tablet nor a touchscreen, so a +machine with nothing else to draw with works out of the box. + +Everything the left button used to do moves to **Ctrl**: Ctrl and the left button select, +move and resize a container, and Ctrl with a double-click centers and fits one. A mouse +reports no pressure, so ink is drawn at an even width, and Calligraphy is the one tool that +still varies because its width comes from speed. The pen path is untouched, so this can be +left on beside a pen. + +## 1.1.5 - 29 August 2026 + +### A word at startup when there is nothing to draw with +When Windows reports neither a pen tablet nor a touchscreen, the application now says so at +startup and explains what it is drawing with instead. Dismissable from the notice or from +Preferences, because the list Windows reports can miss a pen that has never been in range. + +### Setting choices that do not clip their labels +The drawn choices in Preferences — toolbar position, pen button, laser weight — reflow onto +another row instead of squeezing until their labels are cut off mid-word. + +## 1.1.2 - 27 August 2026 + +### Ink over an image, not under it +A stroke drawn across an imported image, text container or LiveView now appears over it +while you are drawing, as it already did once the stroke was finished. + +## 1.1.1 - 26 August 2026 + +### Steadier pen ink, and straight lines +Pen strokes are now collected from the pen's own points rather than from the ink layer, +which keeps pressure and timing intact along the whole stroke. Holding **Shift** rules a +stroke straight, and **Straight line** is available as the pen barrel button action in +Preferences. + +## 1.1.0 - 25 August 2026 + +### SVG images stay vector +SVG files can be imported like any other image, and stay vector — so they are still sharp +after zooming in or scaling the container up. + +## 1.0.3 - 25 August 2026 + +### LiveView stability +Fixes a crash caused by releasing a LiveView frame surface more than once. + +## 1.0.2 - 25 August 2026 + +### LiveView stability +Fixes a crash in Windows Graphics Capture by keeping it on the UI thread. + +## 1.0.1 - 25 August 2026 + +### LiveView stability in the Store build +Fixes a crash when a LiveView was resized in the Microsoft Store build. + +## 1.0.0 - 23 August 2026 + +### The pen says what a tap would do +While the pen hovers, the board shows what touching down would do: the laser with its halo +and speed trail, a dashed square around what the eraser would clear, and a high-contrast +dot for everything else. All of them disappear on contact. + +### 1.0 +Everything 1.0 was waiting on had shipped: Preferences, `.wimport` recipes, Explorer and +VS Code previews, the documentation site, and finger drawing. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 78fb515..e3ca848 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,6 +64,13 @@ need not be publication quality. an unsigned assembly would ship beside a signed executable unnoticed. This has happened once already. +**Bumping the version means writing the release notes.** A pull request that changes +`VersionPrefix` in `Directory.Build.props` must add a matching `## - ` +section to `CHANGELOG.md`, or the **Release notes** check fails. Write what a person gets +by upgrading, not what the diff did — that file becomes the GitHub release body and the +[What's new](https://whiteboard.sqlbi.com/changelog.html) page, so it is the only version +history most people will ever read. Pre-release Dev builds need no entry. + **Brand assets are generated.** Only `src/SQLBI.Whiteboard/Assets/SQLBI.Whiteboard.svg` is authored. Icons, installer artwork, and web assets come from `scripts/build-assets.ps1`, and hand edits are lost on the next run. Colors must change in both the SVG and diff --git a/docs/release-management.md b/docs/release-management.md index 6896e42..a9d10d2 100644 --- a/docs/release-management.md +++ b/docs/release-management.md @@ -12,7 +12,8 @@ itself. Do not run it to “release” anything. | You want to | Do this | | --- | --- | | Land a change | Open a pull request against `main`. The **Pull request** Action builds and tests; merge when it is green. | -| Ship a Whiteboard pre-release | Merge to `main` (anything except `docs/`, `site/`, `vscode/`, and top-level markdown). Azure Pipelines **SQLBI Whiteboard** signs and publishes the GitHub prerelease. To rebuild an existing commit: Azure DevOps → that pipeline → **Run pipeline**. Do not use **Re-run**. | +| Ship a Whiteboard pre-release | Merge to `main` (anything except `docs/`, `site/`, `vscode/`, `CHANGELOG.md`, and top-level markdown). Azure Pipelines **SQLBI Whiteboard** signs and publishes the GitHub prerelease. To rebuild an existing commit: Azure DevOps → that pipeline → **Run pipeline**. Do not use **Re-run**. | +| Say what a release gives people | Add a `## - ` section to `CHANGELOG.md`, in the same pull request that bumps `VersionPrefix`. The **Release notes** check fails without it. That one file becomes both the GitHub release body and the [What's new](https://whiteboard.sqlbi.com/changelog.html) page. | | Promote that build to a full release | Approve the **Release** stage of the same Azure run. Nothing is rebuilt. | | Ship a VS Code extension update | Bump `version` in `vscode/sqlbi-whiteboard/package.json` in a pull request and merge. The **Publish VS Code extension** Action publishes `sqlbi.sqlbi-whiteboard` if that version is not already on the Marketplace. To retry: Actions → **Publish VS Code extension** → **Run workflow**. | | Update whiteboard.sqlbi.com | Merge a change under `site/`. The **Publish site** Action deploys. To retry: Actions → **Publish site** → **Run workflow**. | @@ -132,6 +133,37 @@ variables → Actions**. Forks never receive it. when that tree changes on `main`, when a release is published, and on **Run workflow**. `site/CNAME` carries the custom domain. +### Release notes + +`CHANGELOG.md` is the only place release notes are written, and `scripts/release-notes.ps1` +is the only thing that reads it. One `## - ` section per released version, +one `###` heading per thing a person would notice. + +It has three readers, and none of them can be satisfied by the other two: + +- The **Release notes** check on every pull request fails when `Directory.Build.props` + changes `VersionPrefix` and no section exists for the new version. This is the gate that + matters: the notes get written while the change is fresh, by the person who made it. +- **Azure Pipelines** writes that section into the GitHub release body. It used to be the + single line `SQLBI Whiteboard .`, which told a reader nothing; `addChangeLog` + would have told them a list of commit subjects, which is not the same as what they get. + The step runs before the release is created, so an unwritten changelog stops the release + instead of being noticed afterwards. +- **Publish site** renders every section into `site/changelog.html`, between its + `` and `` markers, and refuses to deploy a + published release that has no section. The page carries the notes as HTML rather than + fetching them from the GitHub API as it used to, so they are readable without scripting + and findable by a search engine. + +Pre-release **Dev** builds are deliberately absent: they come from every merge to `main` +and would bury the releases people actually choose between. The release-time check exempts +them. + +The renderer handles the subset the changelog is allowed to use — `###` headings, +paragraphs, lists, links, `code`, and **bold**. Anything outside that subset appears as +plain text rather than as broken markup, which for a file we write ourselves is a style +rule rather than a limitation. + Two settings outside the repository have to be right, and each fails in its own quiet way: - **Settings → Pages → Source: GitHub Actions.** With the default "Deploy from a branch" diff --git a/installer/winget/SQLBI.Whiteboard.installer.yaml b/installer/winget/SQLBI.Whiteboard.installer.yaml index 95acc34..a03cfaf 100644 --- a/installer/winget/SQLBI.Whiteboard.installer.yaml +++ b/installer/winget/SQLBI.Whiteboard.installer.yaml @@ -16,7 +16,7 @@ # release except the one it was copied from. `wingetcreate update` reads it out of the # downloaded MSI at submission time, which is the only way it can be right. PackageIdentifier: SQLBI.Whiteboard -PackageVersion: 0.9.2 +PackageVersion: 1.2.2 MinimumOSVersion: 10.0.19041.0 InstallerType: wix InstallModes: @@ -24,15 +24,15 @@ InstallModes: - silent - silentWithProgress UpgradeBehavior: install -ReleaseDate: '2026-08-19' +ReleaseDate: '2026-09-02' Installers: - Architecture: x64 Scope: machine - InstallerUrl: https://github.com/sql-bi/SQLBI-Whiteboard/releases/download/v0.9.2/SQLBI.Whiteboard.0.9.2.x64.msi - InstallerSha256: CF7AC4C5F4AED82382811CE00B606D13E99BA08AB9804FD05E68D23E0689CBE9 + InstallerUrl: https://github.com/sql-bi/SQLBI-Whiteboard/releases/download/v1.2.2/SQLBI.Whiteboard.1.2.2.x64.msi + InstallerSha256: 10574E89368DA3E56A4C739C44096A2570F8C1FB9355344BAED197F1E1AA9A21 - Architecture: x64 Scope: user - InstallerUrl: https://github.com/sql-bi/SQLBI-Whiteboard/releases/download/v0.9.2/SQLBI.Whiteboard.0.9.2.x64-userinstaller.msi - InstallerSha256: 9885733D3E0AAEBC39ABC0F142C7461EEA7DE0B5F20CD184A50EACAE19D5BE9B + InstallerUrl: https://github.com/sql-bi/SQLBI-Whiteboard/releases/download/v1.2.2/SQLBI.Whiteboard.1.2.2.x64-userinstaller.msi + InstallerSha256: 2D5E25F28AA9820DA6D20DDFB640456FB4F6D5034E1F932A6DD0637EB816B3ED ManifestType: installer ManifestVersion: 1.6.0 diff --git a/installer/winget/SQLBI.Whiteboard.locale.en-US.yaml b/installer/winget/SQLBI.Whiteboard.locale.en-US.yaml index 1f11525..80e93c5 100644 --- a/installer/winget/SQLBI.Whiteboard.locale.en-US.yaml +++ b/installer/winget/SQLBI.Whiteboard.locale.en-US.yaml @@ -4,7 +4,7 @@ # describing the same application differently is a difference a reader has to resolve, # and there is nothing here worth resolving. PackageIdentifier: SQLBI.Whiteboard -PackageVersion: 0.9.2 +PackageVersion: 1.2.2 PackageLocale: en-US Publisher: SQLBI Corp PublisherUrl: https://www.sqlbi.com diff --git a/installer/winget/SQLBI.Whiteboard.yaml b/installer/winget/SQLBI.Whiteboard.yaml index 7aa73f7..e7d301e 100644 --- a/installer/winget/SQLBI.Whiteboard.yaml +++ b/installer/winget/SQLBI.Whiteboard.yaml @@ -8,7 +8,7 @@ # They are kept here anyway: a submission is a pull request against someone else's # repository, and the version of it that was sent needs to be reviewable in this one. PackageIdentifier: SQLBI.Whiteboard -PackageVersion: 0.9.2 +PackageVersion: 1.2.2 DefaultLocale: en-US ManifestType: version ManifestVersion: 1.6.0 diff --git a/scripts/release-notes.ps1 b/scripts/release-notes.ps1 new file mode 100644 index 0000000..cbbb0c5 --- /dev/null +++ b/scripts/release-notes.ps1 @@ -0,0 +1,247 @@ +<# +.SYNOPSIS + Reads CHANGELOG.md - the one place release notes are written - for the three things + that consume it. + +.DESCRIPTION + The GitHub release body used to be the single line "SQLBI Whiteboard .", and + turning the pipeline's changelog generator on would have replaced it with a list of + commit subjects. Neither says what a person gets by upgrading, so the notes are written + by hand in CHANGELOG.md and this script hands them to whoever needs them: + + Verify - fails when the version being released has no entry. Runs on the pull + request that bumps VersionPrefix, so the notes are written while the + change is fresh, and again when a release is published. + Markdown - writes one version's entry out for the Azure Pipelines release task. + Html - renders every entry into site/changelog.html during the Pages deployment. + + Only released versions are in the file. Pre-release Dev builds are published from every + merge to main and would bury the releases that matter. + +.PARAMETER Mode + Verify, Markdown, or Html. + +.PARAMETER Version + The version to act on, with or without a leading "v". Required by Verify and Markdown, + ignored by Html. + +.PARAMETER Path + The changelog to read. + +.PARAMETER OutFile + Where Markdown writes. Defaults to standard output. + +.PARAMETER Page + The page Html rewrites, between its releases markers. +#> +[CmdletBinding()] +param( + [ValidateSet('Verify', 'Markdown', 'Html')] + [string]$Mode = 'Verify', + [string]$Version, + [string]$Path = 'CHANGELOG.md', + [string]$OutFile, + [string]$Page = 'site/changelog.html' +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +# "## 1.2.2 - 2 September 2026". The version is what the machine reads; everything after it +# is the date, shown as written rather than reformatted. +$headingPattern = '^##\s+(\d+\.\d+\.\d+)\s*[-–—]?\s*(.*)$' + +function Get-Entries([string]$file) { + if (-not (Test-Path $file)) { + throw "No changelog at '$file'." + } + + $entries = [System.Collections.Generic.List[object]]::new() + $current = $null + $body = [System.Collections.Generic.List[string]]::new() + + foreach ($line in (Get-Content $file)) { + if ($line -match $headingPattern) { + if ($current) { + $current.Body = ($body -join "`n").Trim() + $entries.Add($current) + } + + $current = [pscustomobject]@{ + Version = $Matches[1] + Date = $Matches[2].Trim() + Body = '' + } + $body.Clear() + continue + } + + # Any other second-level heading ends the entry rather than joining it. Without + # this a trailing section - "Before 1.0.0" was the one that caught it - is read as + # part of the last release and rendered inside it. + if ($line -match '^##\s') { + if ($current) { + $current.Body = ($body -join "`n").Trim() + $entries.Add($current) + $current = $null + } + + continue + } + + if ($current) { + [void]$body.Add($line) + } + } + + if ($current) { + $current.Body = ($body -join "`n").Trim() + $entries.Add($current) + } + + return $entries +} + +function Get-Entry($entries, [string]$wanted) { + if (-not $wanted) { + throw "-Version is required for $Mode." + } + + $number = $wanted.Trim() -replace '^v', '' + $match = $entries | Where-Object { $_.Version -eq $number } | Select-Object -First 1 + if (-not $match) { + throw @" +$Path has no entry for $number. + +Add a '## $number - ' section saying what a person gets by upgrading, with one '###' +heading per thing they would notice. A release that only fixes something still needs one: +say what broke. Pre-release Dev builds are not listed and need no entry. +"@ + } + + return $match +} + +# Deliberately not a Markdown implementation: it renders the subset CHANGELOG.md is allowed +# to use, and anything outside that subset arrives as plain text rather than as broken +# markup. The changelog is ours, so the subset is a style rule rather than a limitation. +function ConvertTo-Html([string]$markdown) { + function Escape([string]$s) { + return $s.Replace('&', '&').Replace('<', '<').Replace('>', '>') + } + + function Inline([string]$s) { + $s = Escape $s + $s = [regex]::Replace($s, '`([^`]+)`', '$1') + $s = [regex]::Replace($s, '\[([^\]]+)\]\((https?://[^)\s]+)\)', '$1') + $s = [regex]::Replace($s, '\*\*([^*]+)\*\*', '$1') + return $s + } + + $html = [System.Collections.Generic.List[string]]::new() + $paragraph = [System.Collections.Generic.List[string]]::new() + $inList = $false + + function Close-Paragraph { + if ($script:paragraph.Count) { + $script:html.Add('

' + (Inline ($script:paragraph -join ' ')) + '

') + $script:paragraph.Clear() + } + } + + $script:html = $html + $script:paragraph = $paragraph + + foreach ($line in ($markdown -split "`n")) { + $trimmed = $line.Trim() + + if (-not $trimmed) { + Close-Paragraph + if ($inList) { $html.Add(''); $inList = $false } + continue + } + + if ($trimmed -match '^###\s+(.*)$') { + Close-Paragraph + if ($inList) { $html.Add(''); $inList = $false } + $html.Add('

' + (Inline $Matches[1]) + '

') + continue + } + + if ($trimmed -match '^[-*]\s+(.*)$') { + Close-Paragraph + if (-not $inList) { $html.Add('
    '); $inList = $true } + $html.Add('
  • ' + (Inline $Matches[1]) + '
  • ') + continue + } + + [void]$paragraph.Add($trimmed) + } + + Close-Paragraph + if ($inList) { $html.Add('
') } + return ($html -join "`n") +} + +$entries = Get-Entries $Path + +switch ($Mode) { + 'Verify' { + $entry = Get-Entry $entries $Version + Write-Host "$Path has notes for $($entry.Version) ($($entry.Date))." + } + + 'Markdown' { + $entry = Get-Entry $entries $Version + if ($OutFile) { + $directory = Split-Path -Parent $OutFile + if ($directory -and -not (Test-Path $directory)) { + New-Item -ItemType Directory -Path $directory -Force | Out-Null + } + + Set-Content -Path $OutFile -Value $entry.Body -Encoding utf8NoBOM + Write-Host "Wrote the $($entry.Version) notes to $OutFile." + } + else { + $entry.Body + } + } + + 'Html' { + if (-not (Test-Path $Page)) { + throw "No page at '$Page'." + } + + $sections = foreach ($entry in $entries) { + # The separator is a character rather than a CSS gap: without it, "1.2.2" and + # "2 September 2026" run together into "1.2.22 September 2026" wherever the + # stylesheet does not reach - a reader view, a feed, a plain-text scrape. + $date = if ($entry.Date) { + "·$($entry.Date)" + } + else { '' } + @" +
+

$($entry.Version)$date

+$(ConvertTo-Html $entry.Body) +
+"@ + } + + # Markers rather than a whole generated page: the surrounding chrome - nav, footer, + # the explanation of the two channels - is hand-written and has nothing to do with + # any release. + $start = '' + $end = '' + $text = Get-Content $Page -Raw + if ($text -notmatch [regex]::Escape($start) -or $text -notmatch [regex]::Escape($end)) { + throw "'$Page' is missing the $start and $end markers this writes between." + } + + $replacement = $start + "`n" + ($sections -join "`n") + "`n" + $end + $pattern = [regex]::Escape($start) + '.*?' + [regex]::Escape($end) + $updated = [regex]::Replace($text, $pattern, { $replacement }, 'Singleline') + Set-Content -Path $Page -Value $updated -Encoding utf8NoBOM + Write-Host "Wrote $($entries.Count) release$(if ($entries.Count -ne 1) { 's' }) into $Page." + } +} diff --git a/site/changelog.html b/site/changelog.html index a8a56d6..81099b8 100644 --- a/site/changelog.html +++ b/site/changelog.html @@ -3,14 +3,14 @@ -Changelog · SQLBI Whiteboard - +What's new · SQLBI Whiteboard + - - + + @@ -36,8 +36,8 @@
Project -

Changelog

-

GitHub Releases is the source of truth. This page lists what has been published. Notes for each build live on the release itself.

+

What's new

+

What each released version gives you that the one before it did not. The same notes appear on the GitHub release for that version.

@@ -47,11 +47,23 @@

Changelog

Two channels

The released installer is SQLBI Whiteboard. The pre-release installer is SQLBI Whiteboard (Dev). They are separate products: different folders, different settings, different upgrade codes. Only the released channel registers .wboard and .wimport, so uninstalling Dev cannot break those associations.

-

Published builds

-

Without scripting, use All releases.

- +

Released versions

+

Newest first. Pre-release Dev builds are published from every merge and are + not listed here; they are on + GitHub Releases, + along with the installers and the technical detail for every version below.

+ + + +

The release list is written into this page when the site is deployed. Until then, see + All releases.

+ + +

Versions before 1.0.0, published between 17 and 21 August 2026, built the application + up to its first stable version. They are listed with their notes on + GitHub Releases.