Skip to content

lofimichael/beereader

Repository files navigation

Beereader

A native macOS reader for Beehiiv newsletters. Hardcoded to Cellular Thinking for v1, with an editorial reading experience (warm linen, serif body, drop caps, progress bar), archive browsing, auto-updates via Sparkle, and signed + notarized distribution.

Development

Requires Xcode 26+ and macOS 14+.

swift build
swift test
swift run Beereader

For a signed/notarized local build (requires DEVELOPER_ID, TEAM_ID, NOTARY_APPLE_ID, NOTARY_PASSWORD in the environment):

./package.sh
# → dist/Beereader-<VERSION>.dmg

Without those vars the script still produces an unsigned .app and .dmg for local smoke-testing.

Releasing

Releases are driven entirely by the VERSION file.

To ship a new version:

  1. Bump VERSION (e.g. 0.2.50.2.6).
  2. Update CFBundleShortVersionString and CFBundleVersion in Resources/Info.plist to match.
  3. Commit, open a PR, merge to main.

That's it — no git tag, no manual release. When the merge lands on main, CI:

  1. Builds + tests (build-and-test job).
  2. If VERSION doesn't yet have a matching v$VERSION tag, the auto-tag job creates and pushes it.
  3. The package job checks out that tag and runs the full pipeline: package.sh → signed .app → notarized → stapled → DMG → GitHub Release → Sparkle-signed → docs/appcast.xml pushed to GitHub Pages.

Sparkle clients installed in the wild pick up the new build from the appcast automatically.

If VERSION wasn't bumped, auto-tag no-ops and the package job is skipped — the merge is a normal code-only change.

Manual tagging still works

If you ever need to cut a release outside the main-push flow (e.g. hotfix from a branch), you can still git tag v0.2.x && git push --tags directly. The existing tag-push trigger takes that path through the same package job and skips auto-tag.

Secrets required in GitHub Actions

Secret Purpose
CERTIFICATE_P12 base64-encoded Developer ID Application .p12
CERTIFICATE_PASSWORD password for the .p12 above
APPLE_TEAM_ID 10-char team ID (e.g. ABC123DEFG)
APPLE_ID Apple ID email used for notarization
APPLE_ID_PASSWORD app-specific password (NOT your Apple ID password)
SPARKLE_PRIVATE_KEY ed25519 private key used to sign the DMG in the appcast

No extra PAT is required — auto-tag uses the default GITHUB_TOKEN.

Layout

Sources/Beereader/
├── App/            BeereaderApp.swift       — @main entry, window config
├── Models/         Article.swift, Publication.swift
├── Services/       FeedService, ArticleCache, ImageCache, HTMLSanitizer,
│                   ArticleRenderer, ReadStateService, ReadingTime,
│                   UpdateService (Sparkle), NotificationService
├── Utilities/      ResourceLoader                 — bypasses Bundle.module in packaged .app
└── Views/          ContentView, WebViewCoordinator, ArchiveSidebar,
                    WelcomeView, StateViews, HexagonMark
Resources/          Info.plist, Beereader.icns, directory.json
Sources/Beereader/Resources/
                    reader.css, Source Serif 4 + IBM Plex Sans WOFF2s,
                    author-sprite.png
docs/               index.html (landing page), appcast.xml (Sparkle feed),
                    screenshot.png

License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors