Skip to content

ci: automate releases when upstream Syncthing publishes a new version - #297

Open
asavageiv wants to merge 2 commits into
syncthing:v2from
asavageiv:automation/upstream-release-pipeline
Open

asavageiv wants to merge 2 commits into
syncthing:v2from
asavageiv:automation/upstream-release-pipeline

Conversation

@asavageiv

@asavageiv asavageiv commented Sep 10, 2026

Copy link
Copy Markdown

AI usage note: I generated this with the help of Claude Opus at XHigh effort. I've reviewed every line myself. I am a professional software engineer with 15+ years of experience and was a senior SWE at a FANG company.

The build-syncthing-macos changes can be dropped if desired and are definitely more of a guess on my part because I'm not super familiar with the release process. At lease the auto-PR to bump the release version might be useful just as an automatic notification that there's a new reason to release/update syncthing-macos. If we don't want the auto push to Sparkle just from merging the bump PR, let me know and I can adjust.

Summary

Automates the currently-manual release process so a new syncthing-macos release is produced whenever upstream syncthing/syncthing publishes a new stable v2 version. A maintainer merges a bump PR before any signed binary is built and shipped to the Sparkle auto-updater.

Motivation

Releasing is manual today:

  1. Run make update-release locally to bump syncthing/Info.plist + syncthing/Scripts/syncthing-resource.sh to the latest upstream tag.
  2. Commit/push to v2build-syncthing-macos.yml builds + signs the DMG and submits it for notarization (without waiting or stapling).
  3. Someone manually downloads the artifact and creates the GitHub Release + attaches the DMG.
  4. Someone manually dispatches generate-appcast.yml to refresh the Sparkle feed.

This PR closes the manual gaps and adds detection of new upstream releases.

Flow

[schedule: daily]                         (maintainer)         [push to v2]
update-upstream-release.yml  ──opens──▶  bump PR  ──merge──▶  build-syncthing-macos.yml
  • make update-release                                          • build-release  (sign DMG)
  • diff? → open/update PR to v2                                 • notarize       (submit --wait + staple)
                                                                 • publish-release (NEW, guarded on new tag)
                                                                 • regenerate-appcast (NEW)

Changes

New — .github/workflows/update-upstream-release.yml

  • Runs daily on schedule (06:00 UTC) and on-demand via workflow_dispatch.
  • Reuses the existing cmd/update-release/update-release.py to rewrite the packaging metadata to the latest upstream stable v2 release.
  • Opens a version-bump PR against v2 only when the version actually changes; idempotent per version (re-runs refresh the same branch/PR).
  • Touches only packaging metadata — never the signing path — so a human reviews the bump first.

Changed — .github/workflows/build-syncthing-macos.yml

  • notarize: now xcrun notarytool submit --wait, fails the job unless the status is Accepted, then xcrun stapler staples the ticket into the DMG and uploads the stapled artifact. (Previously fire-and-forget, never stapled.)
  • New publish-release: creates the GitHub Release with the notarized DMG, deriving the tag from the DMG name (Syncthing-2.1.5-1.dmgv2.1.5-1). Guarded so it only fires when the tag is new — ordinary v2 pushes stay inert, and merging a bump PR cuts exactly one release.
  • New regenerate-appcast: triggers the existing generate-appcast.yml via gh workflow run, only when a new release was actually published.

Design decisions

  • PR-gated — one maintainer merge before signed binaries ship to auto-update.
  • Stable releases only — matches update-release.py's allow_prerelease=False default.

⚠️ Repo settings this relies on

  • Settings → Actions → General → Workflow permissions → "Allow GitHub Actions to create and approve pull requests" must be enabled, otherwise the bump job cannot open its PR (fails with GitHub Actions is not permitted to create or approve pull requests). Alternative: change the gh pr create step to use a PAT / GitHub App token.
  • The existing signing and appcast environment secrets are used unchanged.

Testing

Ran update-upstream-release.yml via workflow_dispatch in a fork: it detected upstream v2.1.5, bumped Info.plist + syncthing-resource.sh, pushed the branch, and attempted to open the bump PR. The only blocker was the "Allow GitHub Actions to create PRs" toggle above. The full signed → notarize → staple → publish → appcast path depends on the repo's environment secrets (which forks don't inherit) and will first run on merge here.

Notes / limitations

  • A wrapper-only change that reuses the same upstream Syncthing version won't auto-cut a release; that still needs a manual distVersion bump (the -1 suffix), as today.
  • PRs opened with the default GITHUB_TOKEN don't trigger the PR's own debug build (GitHub anti-recursion); the real build runs post-merge on v2. Use a PAT/App token if PR-time CI is desired.

🤖 Generated with Claude Code

Add a PR-gated, fully GitHub-native release pipeline:

- New update-upstream-release.yml: a daily (and on-demand) job that
  detects a new upstream syncthing/syncthing stable v2 release, runs the
  existing cmd/update-release bump script, and opens a version-bump PR
  against v2. It only touches the packaging metadata, so a human reviews
  the bump before any signed binary is built.

- build-syncthing-macos.yml: make notarization real (submit --wait, fail
  on non-Accepted status, then staple the ticket into the DMG) and add
  two jobs that run after a bump PR is merged to v2:
    * publish-release: create the GitHub Release with the notarized DMG,
      guarded so it only fires when the version tag is new (ordinary v2
      pushes stay inert).
    * regenerate-appcast: trigger generate-appcast.yml so the Sparkle
      auto-updater feed is refreshed, only when a new release was cut.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@asavageiv
asavageiv marked this pull request as ready for review September 10, 2026 11:44
@asavageiv

Copy link
Copy Markdown
Author

I'd say the biggest risk here is the --wait on the notary. That burns some extra macos runner minutes. Since releases are rare and it's better to burn machine time than human time, it's probably worth it, but if it's not we can at least keep the automation up to sending the notary and make the stapling step and sparkle update a separate GH action.

Add `--timeout 30m` to `notarytool submit --wait` so a stuck submission
fails fast instead of holding the macOS runner up to the 6h job limit.
Normal submissions finish in 1-5 min; this is just a safety ceiling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant