From bd00906f67b4642065f9f61c704683436b5e38c5 Mon Sep 17 00:00:00 2001 From: PathGao Date: Thu, 13 Aug 2026 03:04:13 +0800 Subject: [PATCH 1/4] docs: bring the release runbook and the syntax reference up to 2.7.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four claims in the docs describe behaviour that PRs since 2.7.3 changed, and two features shipped without reaching the file that documents what Markpad can do. RELEASING.md - snapcraft.yaml no longer builds the app; it unpacks the release's own .deb (#579), so the `npm ci` note and the `rust-deps` troubleshooting row both described a file that no longer exists in that shape (#577). - The .deb/.rpm coverage note still said *Check for Updates…* offers an update and then fails to install it. #573 asks `self_update_supported` first, so it says where updates come from instead. - Adds the AppImage checks (#584, #658) as their own troubleshooting row, and notes that release builds are serialized (#612). README, README.zh-CN - The same pre-#573 claim, in both languages. The Chinese one also told .deb/.rpm users to update "through their distribution channels", which is the sentence #566 removed from the English one — there is no apt or dnf repository. snapcraft.yaml - The comment pointed at .github/workflows/test_snap.yml, deleted in #601. samples/markdown-syntax{,.zh-CN}.md - Lists: Enter continues the marker, Tab changes level, Enter on an empty item leaves the list (#636), and the three list chords (#652). - Tables: cell, row and column keys, why deleting a row has no chord (#645, #653). - Links: Ctrl/Cmd+K (#652). npm test 904 pass, vitest 365 pass. Co-Authored-By: Claude Opus 5 --- README.md | 2 +- README.zh-CN.md | 4 +++- RELEASING.md | 12 +++++++++--- samples/markdown-syntax.md | 18 ++++++++++++++++++ samples/markdown-syntax.zh-CN.md | 18 ++++++++++++++++++ snapcraft.yaml | 8 +++++--- 6 files changed, 54 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 868ef53c..d8830fc3 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ The two Windows files differ only in that one installs and one does not — `-se > After a direct `.dmg` (macOS), `*-setup.exe` (Windows NSIS) or `.AppImage` (Linux) install, Markpad self-updates from GitHub releases via the in-app *Check for Updates…* entry (macOS app menu, or Settings elsewhere). Chocolatey and Snap keep Markpad current through those package managers instead. > -> **`.deb` and `.rpm` are one-time installs.** `tauri-plugin-updater` cannot replace a package-managed install, and there is no apt or dnf repository to update from — upgrading means downloading a newer package from the releases page. *Check for Updates…* will report that a newer version exists but cannot install it ([#570](https://github.com/sftwrdotdev/Markpad/issues/570)). +> **`.deb` and `.rpm` are one-time installs.** `tauri-plugin-updater` cannot replace a package-managed install, and there is no apt or dnf repository to update from — upgrading means downloading a newer package from the releases page. *Check for Updates…* recognises a package-managed install and says where its updates come from, rather than offering one it cannot install ([#570](https://github.com/sftwrdotdev/Markpad/issues/570)). ## What Markpad renders diff --git a/README.zh-CN.md b/README.zh-CN.md index ba4ba394..8ba1288a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -74,7 +74,9 @@ sudo snap install markpad 两个 Windows 文件的区别只在装不装:`-setup.exe` 会把 Markpad 装进 Program Files 和开始菜单,不带 `-setup` 的那个放哪儿就在哪儿运行。 -> 通过 `.dmg`(macOS)、`*-setup.exe`(Windows NSIS)或 `.AppImage`(Linux)直接安装之后,Markpad 会通过应用内的 *检查更新…*(macOS 在应用菜单,其它平台在设置里)从 GitHub 发行版自更新。Snap、Chocolatey、`.deb` 和 `.rpm` 的用户请继续通过各自的分发渠道更新。 +> 通过 `.dmg`(macOS)、`*-setup.exe`(Windows NSIS)或 `.AppImage`(Linux)直接安装之后,Markpad 会通过应用内的 *检查更新…*(macOS 在应用菜单,其它平台在设置里)从 GitHub 发行版自更新。Snap 和 Chocolatey 的更新由这两个包管理器负责。 +> +> **`.deb` 和 `.rpm` 是一次性安装。** `tauri-plugin-updater` 替换不了由包管理器装上的文件,也没有 apt 或 dnf 源可以更新 —— 升级要去发行页面下载新的安装包。*检查更新…* 会认出这类安装,直接告诉你更新从哪来,而不是给你一个装不上的更新([#570](https://github.com/sftwrdotdev/Markpad/issues/570))。 ## Markpad 能渲染什么 diff --git a/RELEASING.md b/RELEASING.md index 34382b41..32959d09 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -60,7 +60,9 @@ The failure is quiet and unfixable from here: `latest.json` 404s, the updater re ## Per-release workflow -The workflow uses `npm ci`, so its installed dependency graph is exactly the committed lockfile. Do not replace it with `npm install` in release jobs. The same applies to [`snapcraft.yaml`](snapcraft.yaml), which builds the snap outside GitHub Actions; `scripts/releaseWorkflow.test.ts` guards both. +The workflow uses `npm ci`, so its installed dependency graph is exactly the committed lockfile. Do not replace it with `npm install` in release jobs. `scripts/releaseWorkflow.test.ts` guards that. + +[`snapcraft.yaml`](snapcraft.yaml) no longer builds anything. It packages the `.deb` the release already shipped (`plugin: dump`, `source-type: deb`), so the snap carries the same binary as the `.deb` and the AppImage rather than a second compilation of the same source — which is also what removed rust and node from a file that had failed four release attempts on them. The same test asserts it is packaging rather than building. 1. **Bump the version:** ```bash @@ -84,6 +86,9 @@ The workflow uses `npm ci`, so its installed dependency graph is exactly the com 3. **Trigger the workflow:** - GitHub UI: Actions → "Build and Release" → Run workflow → master - Or CLI: `gh workflow run build.yml --ref master` + + Only one release build runs at a time — a second dispatch queues behind the + first instead of racing it to the same draft. 4. **Wait** ~30 min for matrix builds to finish, plus ~2 min for `generate-update-feed`. 5. **Open the draft release** on the [Releases page](https://github.com/sftwrdotdev/Markpad/releases). Verify the assets: - **macOS**: `*.dmg`, `*.app.tar.gz`, `*.app.tar.gz.sig` @@ -116,7 +121,7 @@ Mention this clearly in the release notes for the first auto-update-capable vers - **macOS** uses one universal binary (`darwin-aarch64` + `darwin-x86_64` share the same `.app.tar.gz` and signature). - **Windows** uses NSIS — the auto-updater downloads `*-setup.exe` (verified by `*-setup.exe.sig`) and runs it in `passive` install mode. The existing raw portable `.exe` distribution path is preserved alongside, so users who download the portable `.exe` directly continue to work; only the auto-updater path uses the NSIS installer. -- **Linux**: only `AppImage` users get auto-updates — `tauri-plugin-updater` doesn't support `.deb` or `.rpm`, and there is no apt or dnf repository either. `.deb` and `.rpm` are therefore one-time installs: those users upgrade by downloading a newer package. *Check for Updates…* still offers them the update and then fails to install it, because `__TAURI_BUNDLE_TYPE` is not patched into the Linux binary and every Linux package therefore takes the AppImage install path — see #570. This is stated in the README as well; if a repository is ever published, both change together. +- **Linux**: only `AppImage` users get auto-updates — `tauri-plugin-updater` doesn't support `.deb` or `.rpm`, and there is no apt or dnf repository either. `.deb` and `.rpm` are therefore one-time installs: those users upgrade by downloading a newer package. Since #573 the app asks `self_update_supported` *before* it checks, so those installs are told where their updates come from instead of being offered one that then fails to install — `__TAURI_BUNDLE_TYPE` is not patched into the Linux binary, so every Linux package would otherwise take the AppImage install path (#570). This is stated in the README as well; if a repository is ever published, both change together. - **Snap / Chocolatey**: independent distribution channels, published by `publish-packages.yml` after the release is published. Their update mechanisms are unaffected. The Chocolatey package wraps the release's own `Markpad__x64.exe` rather than a second build, which is what `packaging/choco/tools/VERIFICATION.txt` promises. ## Troubleshooting @@ -129,7 +134,8 @@ Mention this clearly in the release notes for the first auto-update-capable vers | Users don't see the update | (1) Did you click *Publish release*? Drafts aren't visible to clients. (2) Is the user on a version older than the first auto-update-capable release? They need a one-time manual reinstall. | | Update download succeeds but install fails with signature error | Pubkey mismatch — the Secrets and `tauri.conf.json` `pubkey` belong to different keypairs. | | `Strip host-coupled libraries from AppImage` fails | Run [`scripts/strip-appimage.sh`](scripts/strip-appimage.sh) locally against the AppImage from the draft release — it needs no signing key. It failed in two of the three v2.7.2 attempts, once because `signer sign` had a stray flag and once because it was reading the deprecated `TAURI_PRIVATE_KEY` names on a CLI too old to accept the current ones. | -| `Publish Packages` / snap job fails | Read the snapcraft error rather than re-running: `Environment validation failed for part 'markpad'` means the `rust-deps` part in `snapcraft.yaml` is gone or renamed. Fix, then re-run the workflow with the tag as `workflow_dispatch` input. | +| `Publish Packages` / snap job fails | Read the snapcraft error rather than re-running. `snapcraft.yaml` only unpacks a `.deb` now, so the two live failures are: the job did not put `markpad.deb` next to the file (the message names the path), or the `snapcraft` snap the runner installed that day changed under us — the job prints `snap list snapcraft`, and an 8.14.5 → 9.0.1 bump is exactly what killed the snap for three months. Fix, then re-run the workflow with the tag as `workflow_dispatch` input. | +| An AppImage check fails in `test_build.yml` | Three scripts run against it and say which one: [`check-appimage-libraries.sh`](scripts/check-appimage-libraries.sh) (what it bundles), [`strip-appimage.sh`](scripts/strip-appimage.sh) (removing the host-coupled ones), [`smoke-appimage.sh`](scripts/smoke-appimage.sh) (whether it starts). All three run locally against the AppImage from the draft release and need no signing key; the tooling does not need FUSE. | | `Publish Packages` / chocolatey job fails on push | A version can only be pushed to Chocolatey once. If it is already there, nothing needs doing; if it is not, check `CHOCO_API_KEY`. | ## Out of scope (not handled by this workflow) diff --git a/samples/markdown-syntax.md b/samples/markdown-syntax.md index e285880d..6b3a4442 100644 --- a/samples/markdown-syntax.md +++ b/samples/markdown-syntax.md @@ -147,6 +147,10 @@ A list item can hold anything: - [ ] An unfinished one - [ ] Nested, and also clickable +**The editor writes the markers.** Press `Enter` inside an item and the next line carries the same one: a bullet keeps the character it was written with, a numbered item increments, a task item arrives unticked. `Tab` and `Shift`+`Tab` change the level. `Enter` on an item with nothing in it clears the marker and leaves the list, which is how you get out. + +A list can also be started from the keyboard: `Ctrl`/`Cmd` + `Shift` + `8` for bullets, `7` for numbers, `9` for a task list. + ## 4. Quotes and alerts > An ordinary blockquote. @@ -260,6 +264,18 @@ An empty cell is written with two pipes — `| 1 || 3 |` — which is why the sp |---|---|---| | 1 || 3 | +**None of that has to be typed by hand.** With the caret in a table: + +| Key | Does | +|---|---| +| `Tab` / `Shift`+`Tab` | move to the next / previous cell — `Tab` in the last one appends a row | +| `Ctrl`/`Cmd` + `Enter` | insert a row below, `Shift` for above | +| `Ctrl`/`Cmd` + `Shift` + `C` | insert a column | +| `Ctrl`/`Cmd` + `Shift` + `Backspace` | delete the column | +| `Ctrl`/`Cmd` + `Alt`/`Option` + `T` | insert a table to begin with | + +Every edit reformats the table, so the pipes stay lined up — including in CJK text, where a character is two columns wide. Deleting a row has no key on purpose: putting the caret on the line and deleting it already does that, while editing the pipes on every row to remove a column does not have a by-hand equivalent worth using. Both, and the rest, are in the command palette (`F1`). + ## 7. Thematic breaks Three or more of `-`, `*` or `_` on their own line, all the same rule: @@ -285,6 +301,8 @@ The [CommonMark spec][spec] and the [GFM spec][gfm] disagree in about twenty pla A link to a heading in this document: [back to the table](#what-is-supported-and-what-travels). Type `](#` in the editor and Markpad completes the headings for you. +`Ctrl`/`Cmd` + `K` inserts a link around whatever is selected — the chord four other Markdown editors use for it. + ### Wikilinks Markpad understands Obsidian's spelling and rewrites it before rendering: diff --git a/samples/markdown-syntax.zh-CN.md b/samples/markdown-syntax.zh-CN.md index 82516103..b5c6ec8b 100644 --- a/samples/markdown-syntax.zh-CN.md +++ b/samples/markdown-syntax.zh-CN.md @@ -149,6 +149,10 @@ HTML 实体也认:© — … → & - [ ] 未完成 - [ ] 嵌套的也能点 +**标记由编辑器替你写。** 在列表项里按 `Enter`,下一行会带上同样的标记:符号列表沿用你写的那个字符,有序列表编号递增,任务项默认未勾选。`Tab` 和 `Shift`+`Tab` 换层级。在一个空的列表项上按 `Enter` 会清掉标记、离开列表——这是走出列表的方式。 + +列表也可以直接用键盘起头:`Ctrl`/`Cmd` + `Shift` + `8` 符号列表、`7` 有序列表、`9` 任务列表。 + ## 4. 引用与提示框 > 普通的引用块。 @@ -262,6 +266,18 @@ const nested = true; |---|---|---| | 1 || 3 | +**这些都不用手敲。** 光标在表格里时: + +| 按键 | 作用 | +|---|---| +| `Tab` / `Shift`+`Tab` | 跳到下一个 / 上一个单元格——在最后一格按 `Tab` 会补一行 | +| `Ctrl`/`Cmd` + `Enter` | 在下方插入一行,加 `Shift` 是上方 | +| `Ctrl`/`Cmd` + `Shift` + `C` | 插入一列 | +| `Ctrl`/`Cmd` + `Shift` + `Backspace` | 删掉这一列 | +| `Ctrl`/`Cmd` + `Alt`/`Option` + `T` | 从头插入一张表 | + +每次编辑都会重排整张表,竖线始终对齐——中日韩字符按两列宽算,所以中文表格也齐。删除行故意没有快捷键:把光标放到那一行删掉就是了;而删除一列要在每一行里改竖线且一次都不能错,手工没有等价做法。这两个和其余的表格命令都在命令面板里(`F1`)。 + ## 7. 分隔线 `-`、`*` 或 `_` 三个以上单独成行,三种是同一条线: @@ -287,6 +303,8 @@ ___ 指向本文档某个标题的链接:[回到那张表](#支持什么以及走得出去多远)。在编辑器里输入 `](#`,Markpad 会把标题列出来给你选。 +`Ctrl`/`Cmd` + `K` 给选中的文字套上链接——另外四个 Markdown 编辑器用的都是这个键。 + ### Wikilink Markpad 认识 Obsidian 的写法,并在渲染前把它改写成标准链接: diff --git a/snapcraft.yaml b/snapcraft.yaml index 2471e70c..15b7205b 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -60,9 +60,11 @@ parts: # left to go wrong, because none of it is here. # # `markpad.deb` is put next to this file by the job that runs snapcraft: - # .github/workflows/publish-packages.yml takes it from the release being - # published, and .github/workflows/test_snap.yml from the latest release. - # Missing, snapcraft fails at pull with the path in the message. + # .github/workflows/publish-packages.yml, which takes it from the release + # being published. That is the only thing that executes this file — #601 + # removed the pull-request check — so a change here is first run against a + # published tag. Missing, snapcraft fails at pull with the path in the + # message. markpad: plugin: dump source: markpad.deb From 9789608f077e7e844be63f4d2bcca85c1f8b1bbb Mon Sep 17 00:00:00 2001 From: PathGao Date: Thu, 13 Aug 2026 03:09:11 +0800 Subject: [PATCH 2/4] docs(syntax): drop two design arguments that belong in the PRs, not here The syntax reference carries no issue numbers, no history and no defence of a decision anywhere in its 500 lines; where it does give a reason -- the three deliberate incompatibilities -- the reason tells the reader what to write instead. Two sentences I added argued for the design at the reader: that four other editors use Mod+K, and why deleting a row has no chord while deleting a column does. Neither changes anything the reader would type. What is left of the second is the part that was actually useful: to delete a row, delete its line. --- samples/markdown-syntax.md | 4 ++-- samples/markdown-syntax.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/markdown-syntax.md b/samples/markdown-syntax.md index 6b3a4442..4b46cdaa 100644 --- a/samples/markdown-syntax.md +++ b/samples/markdown-syntax.md @@ -274,7 +274,7 @@ An empty cell is written with two pipes — `| 1 || 3 |` — which is why the sp | `Ctrl`/`Cmd` + `Shift` + `Backspace` | delete the column | | `Ctrl`/`Cmd` + `Alt`/`Option` + `T` | insert a table to begin with | -Every edit reformats the table, so the pipes stay lined up — including in CJK text, where a character is two columns wide. Deleting a row has no key on purpose: putting the caret on the line and deleting it already does that, while editing the pipes on every row to remove a column does not have a by-hand equivalent worth using. Both, and the rest, are in the command palette (`F1`). +Every edit reformats the table, so the pipes stay lined up — including in CJK text, where a character is two columns wide. To delete a row, delete its line. The rest of the table commands are in the command palette (`F1`). ## 7. Thematic breaks @@ -301,7 +301,7 @@ The [CommonMark spec][spec] and the [GFM spec][gfm] disagree in about twenty pla A link to a heading in this document: [back to the table](#what-is-supported-and-what-travels). Type `](#` in the editor and Markpad completes the headings for you. -`Ctrl`/`Cmd` + `K` inserts a link around whatever is selected — the chord four other Markdown editors use for it. +`Ctrl`/`Cmd` + `K` inserts a link around whatever is selected. ### Wikilinks diff --git a/samples/markdown-syntax.zh-CN.md b/samples/markdown-syntax.zh-CN.md index b5c6ec8b..f7d6b434 100644 --- a/samples/markdown-syntax.zh-CN.md +++ b/samples/markdown-syntax.zh-CN.md @@ -276,7 +276,7 @@ const nested = true; | `Ctrl`/`Cmd` + `Shift` + `Backspace` | 删掉这一列 | | `Ctrl`/`Cmd` + `Alt`/`Option` + `T` | 从头插入一张表 | -每次编辑都会重排整张表,竖线始终对齐——中日韩字符按两列宽算,所以中文表格也齐。删除行故意没有快捷键:把光标放到那一行删掉就是了;而删除一列要在每一行里改竖线且一次都不能错,手工没有等价做法。这两个和其余的表格命令都在命令面板里(`F1`)。 +每次编辑都会重排整张表,竖线始终对齐——中日韩字符按两列宽算,所以中文表格也齐。要删掉一行,把那一行删掉就是。其余的表格命令在命令面板里(`F1`)。 ## 7. 分隔线 @@ -303,7 +303,7 @@ ___ 指向本文档某个标题的链接:[回到那张表](#支持什么以及走得出去多远)。在编辑器里输入 `](#`,Markpad 会把标题列出来给你选。 -`Ctrl`/`Cmd` + `K` 给选中的文字套上链接——另外四个 Markdown 编辑器用的都是这个键。 +`Ctrl`/`Cmd` + `K` 给选中的文字套上链接。 ### Wikilink From 263880b7225065fbd281ef6f30027062ed713a3e Mon Sep 17 00:00:00 2001 From: PathGao Date: Thu, 13 Aug 2026 03:13:07 +0800 Subject: [PATCH 3/4] docs(readme): drop the only issue number a reader ever sees #570 was the last issue number in either README, and it was one I added a few days ago. It is a closed bug report, and after #573 the sentence it was attached to describes ordinary behaviour -- so a reader asking "how does my .deb update" now clicks through to a fault that no longer exists. The half-sentence in front of it went for the same reason: "rather than offering one it cannot install" describes what the app used to do. What is left is what the reader needs -- .deb and .rpm are one-time installs, there is no apt or dnf repository, and Check for Updates says so. Both READMEs keep the Report a Bug link, which is the only issue link either of them had before. --- README.md | 2 +- README.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8830fc3..ef1d9aaf 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ The two Windows files differ only in that one installs and one does not — `-se > After a direct `.dmg` (macOS), `*-setup.exe` (Windows NSIS) or `.AppImage` (Linux) install, Markpad self-updates from GitHub releases via the in-app *Check for Updates…* entry (macOS app menu, or Settings elsewhere). Chocolatey and Snap keep Markpad current through those package managers instead. > -> **`.deb` and `.rpm` are one-time installs.** `tauri-plugin-updater` cannot replace a package-managed install, and there is no apt or dnf repository to update from — upgrading means downloading a newer package from the releases page. *Check for Updates…* recognises a package-managed install and says where its updates come from, rather than offering one it cannot install ([#570](https://github.com/sftwrdotdev/Markpad/issues/570)). +> **`.deb` and `.rpm` are one-time installs.** `tauri-plugin-updater` cannot replace a package-managed install, and there is no apt or dnf repository to update from — upgrading means downloading a newer package from the releases page. *Check for Updates…* recognises a package-managed install and tells you so. ## What Markpad renders diff --git a/README.zh-CN.md b/README.zh-CN.md index 8ba1288a..0170fad1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -76,7 +76,7 @@ sudo snap install markpad > 通过 `.dmg`(macOS)、`*-setup.exe`(Windows NSIS)或 `.AppImage`(Linux)直接安装之后,Markpad 会通过应用内的 *检查更新…*(macOS 在应用菜单,其它平台在设置里)从 GitHub 发行版自更新。Snap 和 Chocolatey 的更新由这两个包管理器负责。 > -> **`.deb` 和 `.rpm` 是一次性安装。** `tauri-plugin-updater` 替换不了由包管理器装上的文件,也没有 apt 或 dnf 源可以更新 —— 升级要去发行页面下载新的安装包。*检查更新…* 会认出这类安装,直接告诉你更新从哪来,而不是给你一个装不上的更新([#570](https://github.com/sftwrdotdev/Markpad/issues/570))。 +> **`.deb` 和 `.rpm` 是一次性安装。** `tauri-plugin-updater` 替换不了由包管理器装上的文件,也没有 apt 或 dnf 源可以更新 —— 升级要去发行页面下载新的安装包。*检查更新…* 会认出这类安装并直接告诉你。 ## Markpad 能渲染什么 From 351dd334796c7000b3870a79e8aa0233fa2a6167 Mon Sep 17 00:00:00 2001 From: PathGao Date: Thu, 13 Aug 2026 03:17:27 +0800 Subject: [PATCH 4/4] docs(releasing): cut the post-mortems back out of the runbook This file is what you read on the day you cut a release. Over three days in August I turned it into a runbook with post-mortems threaded through it: which run pushed Chocolatey 2.7.2 at 15:37, that the snap served 2.6.11 for three months and six versions, which two of the three v2.7.2 attempts the AppImage strip failed in, how the 2.7.2/2.7.3 lock skew was found. All true, none of it changes what you do next, and it sits between you and step 5 while a build is running. Test applied to each one: can it change an action taken on release day. Gone: the "Why package managers publish after the release" section entirely -- its one operational sentence (workflow_dispatch works against a published tag, the only way to exercise snapcraft.yaml) moves into step 7, where you would need it. The failure histories in three troubleshooting rows, keeping the symptom and the fix. The placeholder-pubkey era. Two design defences. Kept: reasons that stop you doing the wrong thing -- why not to create anything at alecdotdev/Markpad, why the Cargo.lock bump is the one that gets forgotten. A prohibition without its reason gets deleted as superstition by whoever comes next. 1957 -> 1563 words. The version before I started was 883. --- RELEASING.md | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 32959d09..af9105c5 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -30,7 +30,7 @@ The build workflow reads both at signing time on macOS, Windows, and Linux runne ### 3. Send the public key content -Send the **single-line content** of `~/.tauri/markpad-updater.key.pub` (no comments, no header lines) to the developer who'll commit it to `src-tauri/tauri.conf.json` under `plugins.updater.pubkey`. This already happened for the current keypair — the committed value is the live public key, not a placeholder — so steps 1–3 are kept as history for anyone who ever has to redo the setup. While the field held a placeholder, auto-update was inert: the app surfaced a clean error state instead of contacting the update server. +Send the **single-line content** of `~/.tauri/markpad-updater.key.pub` (no comments, no header lines) to the developer who'll commit it to `src-tauri/tauri.conf.json` under `plugins.updater.pubkey`. The committed value is the live public key — steps 1–3 are here for whoever has to redo the setup, not for the next release. ### 4. CRITICAL: the pubkey is permanent @@ -56,13 +56,13 @@ So: **do not create a repository named `Markpad` under `alecdotdev`, do not fork The failure is quiet and unfixable from here: `latest.json` 404s, the updater reports no update available, and users on old versions simply stop being offered new ones. It is not a code-execution risk — the pinned `pubkey` means whoever serves that URL cannot produce a signature that installs. -**`build.yml` checks this before creating a release.** It fetches that URL and asserts the feed's download URLs still name this repository, so it tests what actually matters rather than whether a repository exists at the old location — occupying it while serving a correct feed would pass, correctly. A network failure warns instead of blocking. +**`build.yml` checks this before creating a release.** It fetches that URL and asserts the feed's download URLs still name this repository. A network failure warns instead of blocking. ## Per-release workflow The workflow uses `npm ci`, so its installed dependency graph is exactly the committed lockfile. Do not replace it with `npm install` in release jobs. `scripts/releaseWorkflow.test.ts` guards that. -[`snapcraft.yaml`](snapcraft.yaml) no longer builds anything. It packages the `.deb` the release already shipped (`plugin: dump`, `source-type: deb`), so the snap carries the same binary as the `.deb` and the AppImage rather than a second compilation of the same source — which is also what removed rust and node from a file that had failed four release attempts on them. The same test asserts it is packaging rather than building. +[`snapcraft.yaml`](snapcraft.yaml) builds nothing. It packages the `.deb` the release already shipped (`plugin: dump`, `source-type: deb`), so the snap carries the same binary as the `.deb` and the AppImage. The same test asserts it is packaging rather than building. 1. **Bump the version:** ```bash @@ -73,8 +73,7 @@ The workflow uses `npm ci`, so its installed dependency graph is exactly the com `[package].version`, and the `Markpad` entry in [`src-tauri/Cargo.lock`](src-tauri/Cargo.lock). The lock is the one that gets forgotten by hand: nothing in the editing loop reads it, so a bump without it - lands green and stays wrong until someone's `cargo build` rewrites the line. - That is how the 2.7.2/2.7.3 skew was found, one release after it shipped. + lands green and stays wrong. It stops there. Committing, tagging and dispatching stay below, on purpose. 2. **Commit, tag, push:** @@ -97,17 +96,7 @@ The workflow uses `npm ci`, so its installed dependency graph is exactly the com - **Linux**: `*.deb`, `*.rpm`, `*.AppImage`, `*.AppImage.sig` - **Update feed**: `latest.json` (one entry per successfully built platform) 6. **Click "Publish release"** — this is the gate. It activates auto-update for all clients pointing at `releases/latest/download/latest.json`, **and** it starts [`publish-packages.yml`](.github/workflows/publish-packages.yml), which pushes to Chocolatey and the Snap Store. -7. **Watch `Publish Packages` finish.** Two independent jobs; either can fail without affecting the release that already went out. Re-run the failed job after fixing, or run the workflow by hand with the tag as input. - -### Why package managers publish after the release, not during the build - -Chocolatey and the Snap Store used to be pushed from inside `build.yml`'s platform matrix, so an irreversible external side effect happened *before* anything decided whether a release existed. - -That is not hypothetical. Chocolatey's `markpad-app` 2.7.2 was published at 15:37 UTC on 2026-08-07 by run `31192564528` — a run that then failed on Linux and produced no release. The release users actually got came out of a different run three hours later. A Chocolatey version cannot be un-pushed. - -Both steps also carried `continue-on-error: true`, which turned a dead channel into a green check: the snap build failed from v2.6.11 onward and the Snap Store went on serving 2.6.11 for three months and six versions, while every release told people to `sudo snap install markpad`. Neither job swallows a failure now. `scripts/releaseWorkflow.test.ts` holds both properties. - -`publish-packages.yml` also takes `workflow_dispatch` with a tag, so it can be exercised against an already-published release without cutting a new one — worth doing after any change to `snapcraft.yaml` or the Chocolatey packaging, since neither is reachable from a pull request. +7. **Watch `Publish Packages` finish.** Two independent jobs, neither swallowing a failure; either can fail without affecting the release that already went out. Fix, then re-run it with the tag as `workflow_dispatch` input — that path also works against an already-published tag, which is the only way to exercise `snapcraft.yaml` or the Chocolatey packaging without cutting a release, since neither is reachable from a pull request. ## First auto-update-capable release @@ -121,7 +110,7 @@ Mention this clearly in the release notes for the first auto-update-capable vers - **macOS** uses one universal binary (`darwin-aarch64` + `darwin-x86_64` share the same `.app.tar.gz` and signature). - **Windows** uses NSIS — the auto-updater downloads `*-setup.exe` (verified by `*-setup.exe.sig`) and runs it in `passive` install mode. The existing raw portable `.exe` distribution path is preserved alongside, so users who download the portable `.exe` directly continue to work; only the auto-updater path uses the NSIS installer. -- **Linux**: only `AppImage` users get auto-updates — `tauri-plugin-updater` doesn't support `.deb` or `.rpm`, and there is no apt or dnf repository either. `.deb` and `.rpm` are therefore one-time installs: those users upgrade by downloading a newer package. Since #573 the app asks `self_update_supported` *before* it checks, so those installs are told where their updates come from instead of being offered one that then fails to install — `__TAURI_BUNDLE_TYPE` is not patched into the Linux binary, so every Linux package would otherwise take the AppImage install path (#570). This is stated in the README as well; if a repository is ever published, both change together. +- **Linux**: only `AppImage` users get auto-updates — `tauri-plugin-updater` doesn't support `.deb` or `.rpm`, and there is no apt or dnf repository either. `.deb` and `.rpm` are therefore one-time installs: those users upgrade by downloading a newer package, and the app's *Check for Updates…* tells them so rather than offering one. This is stated in the README as well; if a repository is ever published, both change together. - **Snap / Chocolatey**: independent distribution channels, published by `publish-packages.yml` after the release is published. Their update mechanisms are unaffected. The Chocolatey package wraps the release's own `Markpad__x64.exe` rather than a second build, which is what `packaging/choco/tools/VERIFICATION.txt` promises. ## Troubleshooting @@ -133,9 +122,8 @@ Mention this clearly in the release notes for the first auto-update-capable vers | `latest.json` missing entirely | The `generate-update-feed` job didn't run — usually because no `*.sig` files were uploaded. Check the `Upload * Artifacts` steps. | | Users don't see the update | (1) Did you click *Publish release*? Drafts aren't visible to clients. (2) Is the user on a version older than the first auto-update-capable release? They need a one-time manual reinstall. | | Update download succeeds but install fails with signature error | Pubkey mismatch — the Secrets and `tauri.conf.json` `pubkey` belong to different keypairs. | -| `Strip host-coupled libraries from AppImage` fails | Run [`scripts/strip-appimage.sh`](scripts/strip-appimage.sh) locally against the AppImage from the draft release — it needs no signing key. It failed in two of the three v2.7.2 attempts, once because `signer sign` had a stray flag and once because it was reading the deprecated `TAURI_PRIVATE_KEY` names on a CLI too old to accept the current ones. | -| `Publish Packages` / snap job fails | Read the snapcraft error rather than re-running. `snapcraft.yaml` only unpacks a `.deb` now, so the two live failures are: the job did not put `markpad.deb` next to the file (the message names the path), or the `snapcraft` snap the runner installed that day changed under us — the job prints `snap list snapcraft`, and an 8.14.5 → 9.0.1 bump is exactly what killed the snap for three months. Fix, then re-run the workflow with the tag as `workflow_dispatch` input. | -| An AppImage check fails in `test_build.yml` | Three scripts run against it and say which one: [`check-appimage-libraries.sh`](scripts/check-appimage-libraries.sh) (what it bundles), [`strip-appimage.sh`](scripts/strip-appimage.sh) (removing the host-coupled ones), [`smoke-appimage.sh`](scripts/smoke-appimage.sh) (whether it starts). All three run locally against the AppImage from the draft release and need no signing key; the tooling does not need FUSE. | +| An AppImage check fails | Three scripts run against it and the log says which: [`check-appimage-libraries.sh`](scripts/check-appimage-libraries.sh) (what it bundles), [`strip-appimage.sh`](scripts/strip-appimage.sh) (removing the host-coupled ones), [`smoke-appimage.sh`](scripts/smoke-appimage.sh) (whether it starts). All three run locally against the AppImage from the draft release; no signing key, no FUSE. | +| `Publish Packages` / snap job fails | Read the snapcraft error rather than re-running. `snapcraft.yaml` only unpacks a `.deb`, so the two live failures are: the job did not put `markpad.deb` next to it (the message names the path), or the `snapcraft` snap the runner installs changed under us — the job prints `snap list snapcraft`. Fix, then re-run with the tag as `workflow_dispatch` input. | | `Publish Packages` / chocolatey job fails on push | A version can only be pushed to Chocolatey once. If it is already there, nothing needs doing; if it is not, check `CHOCO_API_KEY`. | ## Out of scope (not handled by this workflow)