From e6d8012f99ffd3613eecaea1a1afa5a41a47e810 Mon Sep 17 00:00:00 2001 From: Marco Russo Date: Wed, 2 Sep 2026 15:13:48 +0200 Subject: [PATCH 1/2] Bring the winget seed manifests up to 1.2.2 The first submission is still an unmerged pull request, so these files have described 0.9.2 since August. Update the version, the release date, the two installer URLs and the two hashes, taken from the release's own asset digests rather than transcribed. The description is left alone: it is tied to installer/msix/STORE-LISTING.md and the two still match, so moving one without the other would break that. Co-Authored-By: Claude Opus 5 --- installer/winget/SQLBI.Whiteboard.installer.yaml | 12 ++++++------ installer/winget/SQLBI.Whiteboard.locale.en-US.yaml | 2 +- installer/winget/SQLBI.Whiteboard.yaml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) 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 From c30e25931e44a34286ba76eba55d3f3db9d3b5da Mon Sep 17 00:00:00 2001 From: Marco Russo Date: Wed, 2 Sep 2026 15:30:17 +0200 Subject: [PATCH 2/2] Say what each release gives people, in one place The GitHub release body was the single line "SQLBI Whiteboard .", and the alternative the pipeline offered was a list of commit subjects. Neither tells anyone whether an upgrade is worth having. CHANGELOG.md is now the one place release notes are written, and scripts/release-notes.ps1 the only thing that reads it. It has three readers: the Release notes check on a pull request that bumps VersionPrefix, the Azure Pipelines step that writes the GitHub release body, and the Pages deployment that renders every entry into site/changelog.html. That page stops fetching releases from the GitHub API and becomes What's new: curated, released versions only, carried as HTML so it reads without scripting and can be found by a search engine. Entries go back to 1.0.0; earlier versions are left on GitHub, where they were written. Dev builds are exempt everywhere. They come from every merge to main and would bury the releases people actually choose between. The gate is on the version bump rather than only on the release, so the notes are written while the change is fresh rather than remembered under pressure once the release is already public. The release is checked again anyway, because a release need not have come from a bump. Co-Authored-By: Claude Opus 5 --- .azure/pipelines/build-whiteboard.yaml | 29 ++- .github/workflows/publish-site.yml | 21 +++ .github/workflows/pull-request.yml | 36 ++++ CHANGELOG.md | 111 +++++++++++ CONTRIBUTING.md | 7 + docs/release-management.md | 34 +++- scripts/release-notes.ps1 | 247 +++++++++++++++++++++++++ site/changelog.html | 238 +++--------------------- site/compare.html | 2 +- site/contribute.html | 2 +- site/faq.html | 2 +- site/guide.html | 2 +- site/index.html | 2 +- site/privacy.html | 2 +- site/shortcuts.html | 2 +- site/styles.css | 86 ++------- site/wimport.html | 2 +- 17 files changed, 533 insertions(+), 292 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 scripts/release-notes.ps1 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/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.