From a2a027a11be6b583b89d5a21222e5010748b6db8 Mon Sep 17 00:00:00 2001
From: Codefarmer
Date: Sun, 27 Sep 2026 21:24:07 +0100
Subject: [PATCH 1/2] ci: publish as the latest release and download it from
the readme
Releases are no longer pre-releases, so the latest release link works. Each release also carries the stapled disk image as OpenDeviceHub.dmg, which the readme's download button fetches from the latest release, so the link never needs editing.
---
.github/workflows/release.yml | 4 ++--
README.md | 4 ++--
RELEASING.md | 8 ++++----
scripts/release-notes.py | 2 +-
scripts/sign-and-notarize.sh | 6 ++++++
5 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0b8809a..1c39ac1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -183,8 +183,8 @@ jobs:
gh release create "v${version}" \
--title "${version}" \
--notes-file build/release-notes.md \
- --prerelease \
- build/OpenDeviceHub-${version}.dmg build/SHA256SUMS
+ --latest \
+ build/OpenDeviceHub-${version}.dmg build/OpenDeviceHub.dmg build/SHA256SUMS
env:
GH_TOKEN: ${{ github.token }}
diff --git a/README.md b/README.md
index 876a02c..5282716 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
-
+
@@ -30,7 +30,7 @@
## Install
-Download [OpenDeviceHub-0.1.0.dmg](https://github.com/Mastersam07/OpenDeviceHub/releases/download/v0.1.0/OpenDeviceHub-0.1.0.dmg),
+Download [OpenDeviceHub.dmg](https://github.com/Mastersam07/OpenDeviceHub/releases/latest/download/OpenDeviceHub.dmg),
drag OpenDeviceHub to Applications and launch it. Every version, with its checksums, is on
[Releases](https://github.com/Mastersam07/OpenDeviceHub/releases). The app is signed with a Developer ID certificate and
notarized, so there is no Gatekeeper warning, and it updates itself from the app menu.
diff --git a/RELEASING.md b/RELEASING.md
index 6718e83..65e3a4d 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -57,10 +57,10 @@ unsigned build that reaches a release page is worse than a run that stops.
short retention name so you can download and check them.
4. Install the dry run's DMG and use it. `stapler validate` on the app and on the DMG, and
`shasum -c SHA256SUMS` from a different directory.
-5. Run the workflow again with `publish` **true**. It creates the tag and a pre-release with the DMG
- and `SHA256SUMS`. Then point the README's download button and its Install link at the new DMG:
- they download it directly rather than opening the Releases page, and `releases/latest` skips
- pre-releases, so the link has to carry the version.
+5. Run the workflow again with `publish` **true**. It creates the tag and a release marked as the
+ latest, carrying the DMG under its versioned name, the same DMG as `OpenDeviceHub.dmg`, and
+ `SHA256SUMS`. The README's download button and its Install link fetch `OpenDeviceHub.dmg` from the
+ latest release, so they need no edit.
6. **Only once that release page exists**, commit the generated `appcast.xml` to the feed
repository. A feed pointing at a download that is not there yet breaks updates for everyone who
reads it in the meantime.
diff --git a/scripts/release-notes.py b/scripts/release-notes.py
index 740bc93..70d5bbf 100755
--- a/scripts/release-notes.py
+++ b/scripts/release-notes.py
@@ -69,7 +69,7 @@ def main() -> int:
## Known gaps
-This is a pre-release. These are the ones worth knowing before you install it:
+These are the ones worth knowing before you install it:
{limitations}
diff --git a/scripts/sign-and-notarize.sh b/scripts/sign-and-notarize.sh
index 0ca294e..072b37a 100755
--- a/scripts/sign-and-notarize.sh
+++ b/scripts/sign-and-notarize.sh
@@ -36,6 +36,12 @@ echo
echo "== notarize and staple the disk image =="
"${repo_root}/scripts/notarize.sh" "${dmg}"
+echo
+echo "== the same disk image under a name that never changes =="
+# The README's download button fetches this name from the latest release, so it never needs editing.
+cp "${dmg}" "${repo_root}/build/OpenDeviceHub.dmg"
+echo "${repo_root}/build/OpenDeviceHub.dmg"
+
echo
echo "== checksums, from the stapled artifacts =="
"${repo_root}/scripts/checksums.sh"
From b29c14b7409022daef8b545dbbea8fcc30752b60 Mon Sep 17 00:00:00 2001
From: Codefarmer
Date: Sun, 27 Sep 2026 21:26:57 +0100
Subject: [PATCH 2/2] ci: attach the update feed to each release
The signed appcast.xml ships beside the disk images, so the release holds everything the feed commit needs. Installed copies still read the feed from the feed repository, whose URL cannot change.
---
.github/workflows/release.yml | 3 ++-
RELEASING.md | 13 +++++++------
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1c39ac1..a72a62b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -184,7 +184,8 @@ jobs:
--title "${version}" \
--notes-file build/release-notes.md \
--latest \
- build/OpenDeviceHub-${version}.dmg build/OpenDeviceHub.dmg build/SHA256SUMS
+ build/OpenDeviceHub-${version}.dmg build/OpenDeviceHub.dmg build/SHA256SUMS \
+ build/appcast.xml
env:
GH_TOKEN: ${{ github.token }}
diff --git a/RELEASING.md b/RELEASING.md
index 65e3a4d..3c3be9e 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -58,12 +58,13 @@ unsigned build that reaches a release page is worse than a run that stops.
4. Install the dry run's DMG and use it. `stapler validate` on the app and on the DMG, and
`shasum -c SHA256SUMS` from a different directory.
5. Run the workflow again with `publish` **true**. It creates the tag and a release marked as the
- latest, carrying the DMG under its versioned name, the same DMG as `OpenDeviceHub.dmg`, and
- `SHA256SUMS`. The README's download button and its Install link fetch `OpenDeviceHub.dmg` from the
- latest release, so they need no edit.
-6. **Only once that release page exists**, commit the generated `appcast.xml` to the feed
- repository. A feed pointing at a download that is not there yet breaks updates for everyone who
- reads it in the meantime.
+ latest, carrying the DMG under its versioned name, the same DMG as `OpenDeviceHub.dmg`,
+ `SHA256SUMS` and the signed `appcast.xml`. The README's download button and its Install link fetch
+ `OpenDeviceHub.dmg` from the latest release, so they need no edit.
+6. **Only once that release page exists**, commit the release's `appcast.xml` to the feed
+ repository. Installed copies read the feed from there, never from the release, which is why the
+ feed URL can never move. A feed pointing at a download that is not there yet breaks updates for
+ everyone who reads it in the meantime.
7. Confirm an already installed older copy finds the update, verifies it and installs it, ending on
the new version. Do this before announcing anything: a broken updater cannot be fixed by a later
release.