Skip to content

Commit f169379

Browse files
marcosqlbiclaude
andauthored
Say what each release gives people, in one place (#86)
The GitHub release body for a stable version has been the single line `SQLBI Whiteboard <version>.`, and the alternative the pipeline offered — `addChangeLog` — is a list of commit subjects. That is the too-short and the too-verbose you described, and neither answers the only question a reader has: is this upgrade worth having. `CHANGELOG.md` is now the one place release notes are written, and `scripts/release-notes.ps1` the only thing that reads it. One `## <version> - <date>` section per released version, one `###` heading per thing a person would notice. Three readers, none of which the other two can serve: - **Release notes** on every pull request fails when `Directory.Build.props` changes `VersionPrefix` and no section exists for the new version. - **Azure Pipelines** writes that section into the GitHub release body, before the release is created — so an unwritten changelog stops the release instead of being noticed after it is public. Only the `releaseNotes` input of the stable release task changed; nothing in the signing path. - **Publish site** renders every section into `site/changelog.html` and refuses to deploy a published release that has no section. `changelog.html` becomes **What's new**: it no longer fetches releases from the GitHub API and renders their markdown in the browser, so the notes ship as HTML that reads without scripting and can be indexed. The footer link across the site is renamed to match. Entries go back to 1.0.0, written from the merge history; earlier versions stay on GitHub, where their notes already are. Pre-release **Dev** builds are exempt everywhere — they come from every merge 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, by the person who made it. The release is still checked, because a release need not have come from a bump. Verified locally: all three script modes (`Verify`, `Markdown`, `Html`); the pull-request gate against a real bump (1.2.1 → 1.2.2, passes), a no-bump case (skips), and a bump to an unwritten 1.3.0 (exits 1); the rendered page served over HTTP and checked against the site's own stylesheet; and the `Markdown` output confirmed as UTF-8 with its arrows intact. An unstyled render caught `1.2.22 September 2026` — version and date collided when the only separator was a CSS gap — so the separator is now a character in the markup. The generated region is **not** committed, the way the release manifests are not: `site/changelog.html` holds a placeholder between its markers and the deployment fills it, so the page cannot drift from the changelog. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent b1398f8 commit f169379

17 files changed

Lines changed: 533 additions & 292 deletions

‎.azure/pipelines/build-whiteboard.yaml‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ trigger:
6868
# that is byte-identical to the one before it.
6969
- installer/winget
7070
- scripts/build-release-manifests.ps1
71+
# The notes for a release that already exists, and the script that reads them. A
72+
# wording fix should not cut a pre-release; the notes for a version that has not
73+
# shipped arrive with the VersionPrefix bump, which does trigger one.
74+
- CHANGELOG.md
75+
- scripts/release-notes.ps1
7176
# The same reasoning, one file rather than the folder: the rest of installer/msix is
7277
# the package manifest and its assets, which do go into a build. The listing text is
7378
# a record of what was typed into Partner Center by hand and is read by nothing.
@@ -361,6 +366,25 @@ stages:
361366
parameters:
362367
channel: stable
363368

369+
# The release body used to be the one line "SQLBI Whiteboard <version>.", which
370+
# told a reader nothing, and addChangeLog would have replaced it with a list of
371+
# commit subjects, which tells them too much of the wrong kind. Both come from
372+
# CHANGELOG.md instead, so the release page and the What's new page on the site
373+
# carry the same words and those words are written once.
374+
#
375+
# This fails the stage when the version has no entry. That is the point: the
376+
# release has not been created yet when it runs, so an unwritten changelog stops
377+
# the release rather than being noticed after it is public.
378+
- task: PowerShell@2
379+
displayName: 'Take the release notes from CHANGELOG.md'
380+
inputs:
381+
filePath: 'scripts/release-notes.ps1'
382+
arguments: >-
383+
-Mode Markdown
384+
-Version $(AppSemVer)
385+
-OutFile "$(Build.ArtifactStagingDirectory)/release-notes.md"
386+
pwsh: true
387+
364388
- task: GitHubRelease@1
365389
displayName: 'Create the GitHub release'
366390
inputs:
@@ -373,9 +397,8 @@ stages:
373397
# same version twice: bump VersionPrefix instead.
374398
tag: 'v$(AppSemVer)'
375399
title: 'SQLBI Whiteboard $(AppSemVer)'
376-
releaseNotesSource: inline
377-
releaseNotes: |
378-
SQLBI Whiteboard $(AppSemVer).
400+
releaseNotesSource: filePath
401+
releaseNotesFilePath: '$(Build.ArtifactStagingDirectory)/release-notes.md'
379402
assets: '$(Build.ArtifactStagingDirectory)/release/*'
380403
isPreRelease: false
381404
addChangeLog: false

‎.github/workflows/publish-site.yml‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ on:
2525
branches: [main]
2626
paths:
2727
- 'site/**'
28+
- 'CHANGELOG.md'
2829
- 'scripts/build-release-manifests.ps1'
2930
- 'scripts/verify-published-site.ps1'
31+
- 'scripts/release-notes.ps1'
3032
- '.github/workflows/publish-site.yml'
3133
# A release changes what the manifests say without changing anything in site/, so it has
3234
# to redeploy the page as well. This is what keeps the download links current.
@@ -68,6 +70,25 @@ jobs:
6870
GH_TOKEN: ${{ github.token }}
6971
EXPECT_TAG: ${{ github.event.release.tag_name }}
7072

73+
# A released version with no entry in CHANGELOG.md would publish a What's new page
74+
# that does not mention the version people are being offered. Checked here as well as
75+
# on the pull request that bumps VersionPrefix, because a release does not have to
76+
# have come from one. Pre-releases are exempt: Dev builds come from every merge and
77+
# are deliberately not in the changelog.
78+
- name: Check this release has notes
79+
if: github.event_name == 'release' && github.event.release.prerelease == false
80+
shell: pwsh
81+
run: ./scripts/release-notes.ps1 -Mode Verify -Version "$env:RELEASE_TAG"
82+
env:
83+
RELEASE_TAG: ${{ github.event.release.tag_name }}
84+
85+
# Written into the page rather than fetched from the API by the page itself: the
86+
# notes are then in the HTML that ships, so they are readable without scripting and
87+
# findable by a search engine.
88+
- name: Write the release notes into the page
89+
shell: pwsh
90+
run: ./scripts/release-notes.ps1 -Mode Html
91+
7192
- uses: actions/configure-pages@v5
7293

7394
- uses: actions/upload-pages-artifact@v3

‎.github/workflows/pull-request.yml‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,42 @@ jobs:
5656
echo "-> nothing to build: only the site, docs, vscode extension or markdown changed"
5757
fi
5858
59+
# Release notes are written while the change is fresh, in the pull request that bumps the
60+
# version, rather than remembered under pressure once the release is already public. The
61+
# release itself is checked again in publish-site.yml.
62+
notes:
63+
name: Release notes
64+
runs-on: ubuntu-latest
65+
steps:
66+
- uses: actions/checkout@v5
67+
with:
68+
fetch-depth: 0
69+
70+
- name: Check the version bump brings its notes
71+
shell: pwsh
72+
run: |
73+
$ErrorActionPreference = 'Stop'
74+
Set-StrictMode -Version Latest
75+
76+
$base = "origin/$env:BASE_REF"
77+
function Get-VersionPrefix([string]$text) {
78+
if ($text -match '<VersionPrefix>(.*?)</VersionPrefix>') { return $Matches[1].Trim() }
79+
return ''
80+
}
81+
82+
$before = Get-VersionPrefix (git show "${base}:Directory.Build.props" | Out-String)
83+
$after = Get-VersionPrefix (Get-Content Directory.Build.props -Raw)
84+
85+
if ($before -eq $after) {
86+
Write-Host "VersionPrefix is unchanged at $after, so no new notes are due."
87+
return
88+
}
89+
90+
Write-Host "VersionPrefix goes $before -> $after."
91+
./scripts/release-notes.ps1 -Mode Verify -Version $after
92+
env:
93+
BASE_REF: ${{ github.base_ref }}
94+
5995
build:
6096
name: Build and test
6197
needs: changes

‎CHANGELOG.md‎

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# What's new
2+
3+
What a released version gives you that the one before it did not, written for the person
4+
deciding whether to upgrade rather than for the person who wrote the code.
5+
6+
This file is the source for both the [What's new page](https://whiteboard.sqlbi.com/changelog.html)
7+
and the notes on each GitHub release, so it is written once and read in both places. Only
8+
released versions appear. Pre-release **Dev** builds are published continuously from `main`
9+
and are not listed here; their commit history is on GitHub. Nor are the releases before
10+
1.0.0, which built the application up to its first stable version and are on
11+
[GitHub Releases](https://github.com/sql-bi/SQLBI-Whiteboard/releases) with their own notes.
12+
13+
**Adding an entry.** One `## <version> - <date>` heading, then one `###` heading per thing a
14+
person would notice, each with a sentence or two saying what changed and what it is for. A
15+
release with nothing worth noticing still needs an entry — say that it is a fix and what
16+
broke. The heading is parsed by `scripts/release-notes.ps1`, so keep its shape; the prose
17+
under it is ordinary Markdown, and the renderer handles paragraphs, lists, links, `code`
18+
and **bold**.
19+
20+
## 1.2.2 - 2 September 2026
21+
22+
### The Eraser, for a pen that has none
23+
Not every pen has an eraser on its back end, and until now those pens could not reach the
24+
Eraser tool at all — it appears on the toolbar only when finger or mouse drawing puts it
25+
there. **Preferences → Toolbar → Always show the Eraser** keeps it there for the pen too.
26+
It is off by default, so nothing changes for a pen that already erases. In the compact
27+
toolbar layouts the Eraser joins the row of tools rather than taking a row of its own.
28+
29+
### Preferences you can read
30+
Every setting is now one line: a title and a single sentence saying what it is for. The
31+
defaults, the reasoning and the consequences moved behind a chevron, so a category can be
32+
skimmed instead of read. Searching marks what it matched, and marks the chevron when the
33+
match is in the text behind it, and the search box has a button to clear it.
34+
35+
## 1.2.1 - 31 August 2026
36+
37+
### Mouse drawing offers itself
38+
With Mouse drawing off, picking a tool from the toolbar with the mouse now offers to turn
39+
it on. Reaching for the palette with a mouse is the one moment the application can be sure
40+
the question is worth asking — a pen user reaches for it with the pen. The offer appears
41+
once a session, and once declined for good it does not come back.
42+
43+
## 1.2.0 - 30 August 2026
44+
45+
### The mouse can draw
46+
The left mouse button now does what the selected tool does: ink, erase, select, pan, or the
47+
laser. It defaults to on when Windows reports neither a pen tablet nor a touchscreen, so a
48+
machine with nothing else to draw with works out of the box.
49+
50+
Everything the left button used to do moves to **Ctrl**: Ctrl and the left button select,
51+
move and resize a container, and Ctrl with a double-click centers and fits one. A mouse
52+
reports no pressure, so ink is drawn at an even width, and Calligraphy is the one tool that
53+
still varies because its width comes from speed. The pen path is untouched, so this can be
54+
left on beside a pen.
55+
56+
## 1.1.5 - 29 August 2026
57+
58+
### A word at startup when there is nothing to draw with
59+
When Windows reports neither a pen tablet nor a touchscreen, the application now says so at
60+
startup and explains what it is drawing with instead. Dismissable from the notice or from
61+
Preferences, because the list Windows reports can miss a pen that has never been in range.
62+
63+
### Setting choices that do not clip their labels
64+
The drawn choices in Preferences — toolbar position, pen button, laser weight — reflow onto
65+
another row instead of squeezing until their labels are cut off mid-word.
66+
67+
## 1.1.2 - 27 August 2026
68+
69+
### Ink over an image, not under it
70+
A stroke drawn across an imported image, text container or LiveView now appears over it
71+
while you are drawing, as it already did once the stroke was finished.
72+
73+
## 1.1.1 - 26 August 2026
74+
75+
### Steadier pen ink, and straight lines
76+
Pen strokes are now collected from the pen's own points rather than from the ink layer,
77+
which keeps pressure and timing intact along the whole stroke. Holding **Shift** rules a
78+
stroke straight, and **Straight line** is available as the pen barrel button action in
79+
Preferences.
80+
81+
## 1.1.0 - 25 August 2026
82+
83+
### SVG images stay vector
84+
SVG files can be imported like any other image, and stay vector — so they are still sharp
85+
after zooming in or scaling the container up.
86+
87+
## 1.0.3 - 25 August 2026
88+
89+
### LiveView stability
90+
Fixes a crash caused by releasing a LiveView frame surface more than once.
91+
92+
## 1.0.2 - 25 August 2026
93+
94+
### LiveView stability
95+
Fixes a crash in Windows Graphics Capture by keeping it on the UI thread.
96+
97+
## 1.0.1 - 25 August 2026
98+
99+
### LiveView stability in the Store build
100+
Fixes a crash when a LiveView was resized in the Microsoft Store build.
101+
102+
## 1.0.0 - 23 August 2026
103+
104+
### The pen says what a tap would do
105+
While the pen hovers, the board shows what touching down would do: the laser with its halo
106+
and speed trail, a dashed square around what the eraser would clear, and a high-contrast
107+
dot for everything else. All of them disappear on contact.
108+
109+
### 1.0
110+
Everything 1.0 was waiting on had shipped: Preferences, `.wimport` recipes, Explorer and
111+
VS Code previews, the documentation site, and finger drawing.

‎CONTRIBUTING.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ need not be publication quality.
6464
an unsigned assembly would ship beside a signed executable unnoticed. This has happened once
6565
already.
6666

67+
**Bumping the version means writing the release notes.** A pull request that changes
68+
`VersionPrefix` in `Directory.Build.props` must add a matching `## <version> - <date>`
69+
section to `CHANGELOG.md`, or the **Release notes** check fails. Write what a person gets
70+
by upgrading, not what the diff did — that file becomes the GitHub release body and the
71+
[What's new](https://whiteboard.sqlbi.com/changelog.html) page, so it is the only version
72+
history most people will ever read. Pre-release Dev builds need no entry.
73+
6774
**Brand assets are generated.** Only `src/SQLBI.Whiteboard/Assets/SQLBI.Whiteboard.svg` is
6875
authored. Icons, installer artwork, and web assets come from `scripts/build-assets.ps1`, and
6976
hand edits are lost on the next run. Colors must change in both the SVG and

‎docs/release-management.md‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ itself. Do not run it to “release” anything.
1212
| You want to | Do this |
1313
| --- | --- |
1414
| Land a change | Open a pull request against `main`. The **Pull request** Action builds and tests; merge when it is green. |
15-
| 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**. |
15+
| 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**. |
16+
| Say what a release gives people | Add a `## <version> - <date>` 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. |
1617
| Promote that build to a full release | Approve the **Release** stage of the same Azure run. Nothing is rebuilt. |
1718
| 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**. |
1819
| 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.
132133
when that tree changes on `main`, when a release is published, and on **Run workflow**.
133134
`site/CNAME` carries the custom domain.
134135

136+
### Release notes
137+
138+
`CHANGELOG.md` is the only place release notes are written, and `scripts/release-notes.ps1`
139+
is the only thing that reads it. One `## <version> - <date>` section per released version,
140+
one `###` heading per thing a person would notice.
141+
142+
It has three readers, and none of them can be satisfied by the other two:
143+
144+
- The **Release notes** check on every pull request fails when `Directory.Build.props`
145+
changes `VersionPrefix` and no section exists for the new version. This is the gate that
146+
matters: the notes get written while the change is fresh, by the person who made it.
147+
- **Azure Pipelines** writes that section into the GitHub release body. It used to be the
148+
single line `SQLBI Whiteboard <version>.`, which told a reader nothing; `addChangeLog`
149+
would have told them a list of commit subjects, which is not the same as what they get.
150+
The step runs before the release is created, so an unwritten changelog stops the release
151+
instead of being noticed afterwards.
152+
- **Publish site** renders every section into `site/changelog.html`, between its
153+
`<!-- releases:start -->` and `<!-- releases:end -->` markers, and refuses to deploy a
154+
published release that has no section. The page carries the notes as HTML rather than
155+
fetching them from the GitHub API as it used to, so they are readable without scripting
156+
and findable by a search engine.
157+
158+
Pre-release **Dev** builds are deliberately absent: they come from every merge to `main`
159+
and would bury the releases people actually choose between. The release-time check exempts
160+
them.
161+
162+
The renderer handles the subset the changelog is allowed to use — `###` headings,
163+
paragraphs, lists, links, `code`, and **bold**. Anything outside that subset appears as
164+
plain text rather than as broken markup, which for a file we write ourselves is a style
165+
rule rather than a limitation.
166+
135167
Two settings outside the repository have to be right, and each fails in its own quiet way:
136168

137169
- **Settings → Pages → Source: GitHub Actions.** With the default "Deploy from a branch"

0 commit comments

Comments
 (0)