The install commands name no version, so they cannot go stale
A browser download is the one route that does not work on a Mac, and the README said so in a note *below* the commands -- which is no help to somebody who followed the commands. macOS now leads the download section with curl, states why in its first sentence, and Linux follows in the same three lines. Those three lines name no version, because the release now attaches a version-less copy of every binary beside the stamped one. That is what makes releases/latest/download/meshterm-macos-arm64 resolve, so the README points at whichever release is newest instead of at one that was current when somebody last remembered to grep the old number out of it. The stamped files stay for anyone keeping several builds around. And the release page itself now opens with those commands written out for its own version, above the changelog, built from the tag -- so the links in the example are the assets attached to the page printing them. The release skill loses the step that re-pointed the README by hand and gains the asset count to check instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
aed1d91484
commit
3edfaebadc
5 files changed
+214
-66
No files matched your search
@@ -96,23 +96,22 @@ version is written**. `[project] version` in `pyproject.toml` is `dynamic` and h
|
||||
reads the attribute, so the number in a built wheel cannot drift from the number in the
|
||||
source. Do not add a second one.
|
||||
|
||||
### Then re-point the README's download commands
|
||||
### The README needs nothing — deliberately
|
||||
|
||||
`installers.yml` names each asset `meshterm-${version}-<label><ext>`, so **the file a reader
|
||||
downloads is named after the release** — and the README tells them what to type at it. Those
|
||||
lines are prose, not code, so nothing rewrites them for you:
|
||||
It used to. `installers.yml` names each asset `meshterm-${version}-<label><ext>`, so every
|
||||
download command in the README named a version, and every release meant grepping the old
|
||||
number out of five of them. That step failed quietly when it was missed: a README naming
|
||||
last release's file still reads perfectly well, and only breaks for the one person who
|
||||
types it.
|
||||
|
||||
```
|
||||
grep -n '<the previous version>' README.md
|
||||
```
|
||||
`github-release.yml` now attaches a **version-less copy of every binary** beside the
|
||||
stamped one, so `releases/latest/download/meshterm-macos-arm64` is a URL that never moves —
|
||||
which is what the README and `docs/uconsole.md` use. Nothing in either names a version.
|
||||
Leave them alone, and if you find yourself adding a version to an install command, add an
|
||||
alias to the gather step instead.
|
||||
|
||||
Every hit is a download or run command (`.\meshterm-X.Y.Z-windows-x64.exe`,
|
||||
`chmod +x meshterm-X.Y.Z-*`, the `xattr` quarantine note, the `MESHTERM_HOME` trial runs).
|
||||
Replace the old number with the one just bumped to, and re-read each line: they must name
|
||||
the file the workflow is about to publish, or the first thing a new user does fails.
|
||||
|
||||
Also check `docs/cli.md` for a sample document carrying a `"version"` field, which is the
|
||||
live `{version}` placeholder and must show the new number too.
|
||||
What *does* still carry the number: `docs/cli.md` has a sample document with a `"version"`
|
||||
field, which is the live `{version}` placeholder and must show the new one.
|
||||
|
||||
## 5. Commit, tag, push
|
||||
|
||||
@@ -143,16 +142,26 @@ Five platform builds, the release job, and `website` — which rebuilds meshterm
|
||||
tag so the site shows the new version — so it takes a few minutes. If only `website` fails,
|
||||
the release itself is fine (it runs after publishing); the usual cause is the
|
||||
`SITE_DEPLOY_KEY` secret, and once that is fixed `gh run rerun <run-id> --failed` finishes
|
||||
it. **Check the notes
|
||||
actually came out of the changelog** — a green run is not proof, because the fallback is a
|
||||
successful step:
|
||||
it.
|
||||
|
||||
The notes open with an install block the workflow writes from the tag — the same commands
|
||||
as the README, but pinned to *this* release's own assets — and the changelog follows under
|
||||
`## What changed`. **Check that second half actually came out of the changelog**, because a
|
||||
green run is not proof: the fallback is a successful step.
|
||||
|
||||
```
|
||||
gh release view vX.Y.Z --json body --jq .body | head -3
|
||||
gh release view vX.Y.Z --json body --jq .body | sed -n '/## What changed/,$p' | head -5
|
||||
```
|
||||
|
||||
If that reads "No changelog entry for X.Y.Z.", the extraction failed rather than the
|
||||
changelog being empty. Fix the workflow, then repair the published notes in place with
|
||||
changelog being empty.
|
||||
|
||||
Fourteen assets is the right count — five version-stamped binaries, five version-less
|
||||
copies of them, `SHA256SUMS`, and the three licence files:
|
||||
|
||||
```
|
||||
gh release view vX.Y.Z --json assets --jq '.assets | length'
|
||||
``` Fix the workflow, then repair the published notes in place with
|
||||
`gh release edit vX.Y.Z --notes-file` — the binaries are fine and the tag does not move.
|
||||
|
||||
If a *build* fails, the tag is already public: fix forward with a new patch version rather
|
||||
|
||||
@@ -66,14 +66,45 @@ jobs:
|
||||
id: gather
|
||||
shell: bash
|
||||
run: |
|
||||
tag="${{ inputs.tag || github.ref_name }}"
|
||||
version="${tag#v}"
|
||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
mkdir -p release
|
||||
find artifacts -type f -exec mv {} release/ \;
|
||||
ls -lh release/
|
||||
# One combined checksum file is easier to verify against than five loose ones.
|
||||
(cd release && cat *.sha256 > SHA256SUMS && rm -f *.sha256)
|
||||
tag="${{ inputs.tag || github.ref_name }}"
|
||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||
echo "version=${tag#v}" >> "$GITHUB_OUTPUT"
|
||||
cd release
|
||||
|
||||
# A second, version-less copy of every binary. GitHub's evergreen download URL,
|
||||
# `releases/latest/download/<name>`, resolves against an exact asset name and
|
||||
# nothing else — so a link that always fetches the newest build needs a name
|
||||
# that never moves. That is what lets the README, the website and anyone's
|
||||
# install script say `meshterm-macos-arm64` once instead of naming a version
|
||||
# that goes stale the moment the next release lands. The version-stamped file
|
||||
# stays beside it: it is the one you want on disk when you keep several builds
|
||||
# around, and it is what the release-notes install block points at, since that
|
||||
# page is about this release rather than the latest one.
|
||||
made=0
|
||||
for versioned in "meshterm-$version"-*; do
|
||||
case "$versioned" in *.sha256) continue ;; esac
|
||||
[ -e "$versioned" ] || continue
|
||||
stable="meshterm-${versioned#meshterm-$version-}"
|
||||
cp "$versioned" "$stable"
|
||||
sha256sum "$stable" > "$stable.sha256"
|
||||
made=$((made + 1))
|
||||
done
|
||||
# Nothing matched means the tag and `meshterm.__version__` disagree, which is a
|
||||
# broken release either way: the notes below are about to name files by version
|
||||
# that the build did not produce. Fail here, where it is one line to read.
|
||||
if [ "$made" -eq 0 ]; then
|
||||
echo "::error::No binary named meshterm-$version-*; $tag and meshterm.__version__ disagree."
|
||||
exit 1
|
||||
fi
|
||||
echo "$made version-less aliases made"
|
||||
|
||||
# One combined checksum file is easier to verify against than ten loose ones.
|
||||
cat *.sha256 > SHA256SUMS && rm -f *.sha256
|
||||
|
||||
- name: Take the release notes from the changelog
|
||||
id: notes
|
||||
@@ -103,6 +134,72 @@ jobs:
|
||||
fi
|
||||
echo "--- notes ---"; cat notes.md
|
||||
|
||||
# Most people who open a release page came to install the thing, so the commands go
|
||||
# above the changelog rather than in a link to a README that names some other
|
||||
# version. Written here rather than kept as prose anywhere means they can only ever
|
||||
# name *this* release: the tag interpolates, so the URLs are the assets attached to
|
||||
# the very page they are printed on, and there is no example version to go stale.
|
||||
#
|
||||
# The heredoc is quoted, so the markdown's own backticks stay backticks instead of
|
||||
# becoming command substitution, and the two placeholders are filled by `sed`
|
||||
# afterwards. Neither a tag nor a version can contain a slash, so the substitution
|
||||
# needs no escaping.
|
||||
- name: Open the notes with this release's install commands
|
||||
shell: bash
|
||||
env:
|
||||
TAG: ${{ steps.gather.outputs.tag }}
|
||||
VERSION: ${{ steps.gather.outputs.version }}
|
||||
run: |
|
||||
cat > install.md.in <<'INSTALL_MD'
|
||||
## Install
|
||||
|
||||
One file, no Python needed.
|
||||
|
||||
**macOS** — paste these into Terminal. Use `curl`, **not your browser**: a browser
|
||||
flags the download and macOS then refuses to open it at all, and on Sequoia and
|
||||
later right-click → Open no longer gets you past it. `curl` flags nothing, so it
|
||||
simply runs.
|
||||
|
||||
```bash
|
||||
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/download/@TAG@/meshterm-@VERSION@-macos-arm64
|
||||
chmod +x meshterm
|
||||
./meshterm
|
||||
```
|
||||
|
||||
That is the Apple silicon build — every Mac since 2020. On an Intel Mac, swap
|
||||
`arm64` for `x64`.
|
||||
|
||||
**Linux** — the same three lines with `linux-x64`, or `linux-arm64` on a uConsole
|
||||
or another 64-bit ARM handheld.
|
||||
|
||||
```bash
|
||||
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/download/@TAG@/meshterm-@VERSION@-linux-x64
|
||||
chmod +x meshterm
|
||||
./meshterm
|
||||
```
|
||||
|
||||
**Windows** — download [meshterm-@VERSION@-windows-x64.exe](https://github.com/jpmartineau/MeshTerm/releases/download/@TAG@/meshterm-@VERSION@-windows-x64.exe), then run it from Windows
|
||||
Terminal or PowerShell rather than by double-clicking, so you can read anything it
|
||||
says on the way up.
|
||||
|
||||
```powershell
|
||||
.\meshterm-@VERSION@-windows-x64.exe
|
||||
```
|
||||
|
||||
Every file below is listed in `SHA256SUMS`. The version-less copies —
|
||||
`meshterm-macos-arm64` and its four siblings — are the same binaries under a name
|
||||
that never changes, for anything that wants whichever release is newest without
|
||||
being told its number. [Installing with pip or pipx, and the rest of the
|
||||
detail](https://github.com/jpmartineau/MeshTerm#install).
|
||||
|
||||
---
|
||||
|
||||
## What changed
|
||||
INSTALL_MD
|
||||
sed -e "s/@TAG@/$TAG/g" -e "s/@VERSION@/$VERSION/g" install.md.in > install.md
|
||||
cat install.md notes.md > body.md
|
||||
echo "--- body ---"; cat body.md
|
||||
|
||||
- name: Create it
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
@@ -111,7 +208,7 @@ jobs:
|
||||
run: |
|
||||
gh release create "$TAG" release/* \
|
||||
--title "MeshTerm ${TAG#v}" \
|
||||
--notes-file notes.md \
|
||||
--notes-file body.md \
|
||||
--verify-tag \
|
||||
$PRERELEASE
|
||||
echo "https://github.com/${{ github.repository }}/releases/tag/$TAG"
|
||||
|
||||
@@ -17,6 +17,28 @@ allowed to change behaviour, not just add to it.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **Every release page now opens with the commands to install that release.** They are
|
||||
written from the tag, so the URLs in them are the files attached to the page they are
|
||||
printed on — there is no example version to mistype and nothing to go stale. The
|
||||
changelog follows underneath.
|
||||
|
||||
- **A version-less copy of every binary rides along with the stamped one.**
|
||||
`meshterm-macos-arm64` and its four siblings are the same builds under a name that never
|
||||
moves, which is what makes `releases/latest/download/…` a link that always fetches the
|
||||
newest release. The version-stamped files are still there for anyone keeping more than
|
||||
one build around.
|
||||
|
||||
### Changed
|
||||
|
||||
- **The install instructions lead with `curl` on macOS.** Downloading MeshTerm in a browser
|
||||
is the one route that doesn't work on a Mac — the browser flags the file and macOS then
|
||||
refuses to open it, and since Sequoia right-click → Open won't get you past it either.
|
||||
That was true before and said so in a note below the commands, which is no use to
|
||||
somebody who followed the commands. Now it is the macOS instruction, and it is three
|
||||
lines that name no version.
|
||||
|
||||
## [0.3.7] — 2026-09-19
|
||||
|
||||
### Added
|
||||
|
||||
@@ -64,29 +64,64 @@ your mesh's history is worth.
|
||||
|
||||
### Download a build
|
||||
|
||||
**[⬇ Latest release](https://github.com/jpmartineau/MeshTerm/releases/latest)** — one file,
|
||||
no Python needed. Windows, macOS (Intel and Apple silicon), and Linux (x64 and ARM64, so
|
||||
the uConsole is covered).
|
||||
One file, no Python needed — Windows, macOS (Intel and Apple silicon), and Linux (x64 and
|
||||
ARM64, so the uConsole is covered). Every command below fetches the
|
||||
**[⬇ latest release](https://github.com/jpmartineau/MeshTerm/releases/latest)**, whichever
|
||||
one that is, so none of them goes stale.
|
||||
|
||||
MeshTerm is a terminal program, so **open a terminal and run it from there.** You can
|
||||
double-click it and it will work, but you'll get whatever console your system picks, and
|
||||
if anything goes wrong at startup the window closes before you can read why.
|
||||
|
||||
**Windows** — open Windows Terminal or PowerShell, `cd` to your downloads, then:
|
||||
#### macOS — download it with `curl`
|
||||
|
||||
```powershell
|
||||
.\meshterm-0.3.7-windows-x64.exe
|
||||
```
|
||||
|
||||
**macOS and Linux** — open Terminal, `cd` to your downloads, then:
|
||||
**Don't use your browser.** A browser flags the file as downloaded, and macOS then refuses
|
||||
to open it at all — on Sequoia and later, right-click → Open no longer gets you past that
|
||||
either. `curl` flags nothing, so what it hands you simply runs. Open Terminal and paste:
|
||||
|
||||
```bash
|
||||
chmod +x meshterm-0.3.7-*
|
||||
./meshterm-0.3.7-*
|
||||
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/latest/download/meshterm-macos-arm64
|
||||
chmod +x meshterm
|
||||
./meshterm
|
||||
```
|
||||
|
||||
On macOS, downloading it with `curl` instead of a browser saves you a fight with Gatekeeper
|
||||
— the note below has the line.
|
||||
That's the Apple silicon build — every Mac since 2020. On an **Intel** Mac, swap `arm64`
|
||||
for `x64`. And if you already downloaded it with a browser, you don't have to start over:
|
||||
`xattr -d com.apple.quarantine meshterm` clears the flag.
|
||||
|
||||
#### Linux — the same three lines
|
||||
|
||||
`linux-x64` on a PC, `linux-arm64` on a uConsole or another 64-bit ARM handheld.
|
||||
|
||||
```bash
|
||||
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/latest/download/meshterm-linux-x64
|
||||
chmod +x meshterm
|
||||
./meshterm
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
Download
|
||||
**[meshterm-windows-x64.exe](https://github.com/jpmartineau/MeshTerm/releases/latest/download/meshterm-windows-x64.exe)**,
|
||||
then open Windows Terminal or PowerShell, `cd` to your downloads, and run it:
|
||||
|
||||
```powershell
|
||||
.\meshterm-windows-x64.exe
|
||||
```
|
||||
|
||||
Windows says *"Windows protected your PC"* the first time. Click **More info → Run anyway**.
|
||||
|
||||
Whichever you took, you now have a file called `meshterm` — put it somewhere on your
|
||||
`PATH` and it's just `meshterm` from anywhere.
|
||||
|
||||
> **These builds aren't code-signed**, which is why macOS and Windows both push back the
|
||||
> first time; signing costs real money on both platforms and this is a free side project.
|
||||
> Every release ships a `SHA256SUMS` file if you'd rather check what you got, and
|
||||
> [installing with pip or pipx](#or-install-with-pip) sidesteps the whole business, since
|
||||
> nothing arrives as a downloaded binary.
|
||||
>
|
||||
> Each release page also carries these commands written out for **that exact version**,
|
||||
> next to its own downloads.
|
||||
|
||||
### A word about terminals, on Windows
|
||||
|
||||
@@ -115,39 +150,15 @@ it simply switches to it.
|
||||
|
||||
Preferences → Display → Console setup turns all of this off if you'd rather stay put.
|
||||
|
||||
Rename it to something you don't mind typing and put it somewhere on your `PATH`, and it
|
||||
becomes just `meshterm` from anywhere.
|
||||
|
||||
> **Your system will complain the first time, and it's right to.** These builds aren't
|
||||
> code-signed — signing costs real money on both platforms and this is a free side
|
||||
> project.
|
||||
>
|
||||
> - **macOS**: *"cannot be opened because the developer cannot be verified"* — or, on Sequoia
|
||||
> and later, *"Apple could not verify…"*, and right-click → Open no longer gets past it.
|
||||
> The flag that causes it is set by your **browser**, not by macOS, so the easiest answer
|
||||
> is to not use one:
|
||||
>
|
||||
> ```bash
|
||||
> curl -L -O https://github.com/jpmartineau/MeshTerm/releases/download/v0.3.7/meshterm-0.3.7-macos-arm64
|
||||
> chmod +x meshterm-0.3.7-macos-arm64 && ./meshterm-0.3.7-macos-arm64
|
||||
> ```
|
||||
>
|
||||
> `curl` marks nothing, so it simply runs — on an Intel Mac, swap `arm64` for `x64`. If it's
|
||||
> already downloaded, clear the flag instead: `xattr -d com.apple.quarantine meshterm-0.3.7-*`.
|
||||
> Installing with pipx (below) avoids all of this too, since nothing is downloaded as a binary.
|
||||
> - **Windows**: *"Windows protected your PC"*. Click **More info → Run anyway**.
|
||||
>
|
||||
> Every release ships a `SHA256SUMS` file if you'd rather check the download first.
|
||||
|
||||
> **Trying a build without touching your real data.** MeshTerm keeps everything in
|
||||
> `~/.meshterm` — your history database, contacts, channel keys — and *every* copy of
|
||||
> MeshTerm uses that same folder. Set `MESHTERM_HOME` to try one in isolation:
|
||||
>
|
||||
> ```bash
|
||||
> MESHTERM_HOME=~/meshterm-test ./meshterm-0.3.7-* # macOS, Linux
|
||||
> MESHTERM_HOME=~/meshterm-test ./meshterm # macOS, Linux
|
||||
> ```
|
||||
> ```powershell
|
||||
> $env:MESHTERM_HOME = "$HOME\meshterm-test"; .\meshterm-0.3.7-windows-x64.exe
|
||||
> $env:MESHTERM_HOME = "$HOME\meshterm-test"; .\meshterm-windows-x64.exe
|
||||
> ```
|
||||
>
|
||||
> Same variable if you run two radios and want them kept apart.
|
||||
|
||||
+11
-2
@@ -92,8 +92,17 @@ The bridge supports both and prefers the newer one when it finds both installed.
|
||||
|
||||
**MeshTerm itself** — either:
|
||||
|
||||
- the Linux ARM64 one-file release from
|
||||
[the latest release page](https://github.com/jpmartineau/MeshTerm/releases/latest), or
|
||||
- the Linux ARM64 one-file release — three lines, no Python at all:
|
||||
|
||||
```bash
|
||||
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/latest/download/meshterm-linux-arm64
|
||||
chmod +x meshterm
|
||||
./meshterm
|
||||
```
|
||||
|
||||
(That URL always fetches whichever release is newest; the
|
||||
[release page](https://github.com/jpmartineau/MeshTerm/releases/latest) has the
|
||||
version-stamped files and their checksums.) Or:
|
||||
- an install from the repository with `pipx` (Python 3.10 or newer). Plain `pip install`
|
||||
into the system Python is refused on bookworm and trixie; `pipx` (`sudo apt install pipx`)
|
||||
gives MeshTerm a virtual environment of its own.
|
||||
|
||||
Reference in new issue
Block a user