Skip to content

ci: fix appcast publish by keeping SUFeedURL=appcast.xml (mirror LockIME)#5

Merged
BlackHole1 merged 1 commit into
mainfrom
fix/appcast-output-name
Jun 30, 2026
Merged

ci: fix appcast publish by keeping SUFeedURL=appcast.xml (mirror LockIME)#5
BlackHole1 merged 1 commit into
mainfrom
fix/appcast-output-name

Conversation

@BlackHole1

@BlackHole1 BlackHole1 commented Jun 30, 2026

Copy link
Copy Markdown
Member

Problem

The Nightly (Beta) / Release publish job fails at Build appcasts with exit 1, right after:

Wrote 1 new update, updated 0 existing updates, and removed 0 old updates in appcast-arm64.xml

test -f "build/dist-$ARCH/appcast.xml" then fails.

Root cause

generate_appcast can't run the app, so it derives the output appcast filename from the app's SUFeedURL basename. The per-arch split (#3) set Info.plist SUFeedURL to …/appcast-arm64.xml, so the tool writes appcast-arm64.xml in every build/dist-$ARCH dir — but the CI seeds, tests, and publishes the local file build/dist-$ARCH/appcast.xml. Mismatch → exit 1. (The log line …in appcast-arm64.xml is the derived name, not the file actually written.)

Fix — mirror LockIME (no -o)

  • Revert Sources/CloseUp/Info.plist SUFeedURL…/appcast.xml. It is a runtime no-op (UpdaterDelegate.feedURLString pins an explicit per-arch URL for both arches); its only jobs are the generate_appcast naming basis and the 0.1.0 default. With basename appcast.xml, the tool writes the local appcast.xml the CI already expects — no -o needed.
  • The local working file in each build/dist-$ARCH is always appcast.xml (the arch is already in the directory name). The per-arch feed name is applied only at the gh-pages boundary: seed appcast-$ARCH.xml → local appcast.xml; publish local appcast.xmlappcast-$ARCH.xml.
  • CloseUp keeps symmetric feeds (appcast-arm64.xml / appcast-x86_64.xml); appcast.xml stays a frozen 0.1.0 orphan the pipeline never writes. Unlike LockIME (legacy arm64-only, so its arm64 feed is appcast.xml), CloseUp's universal 0.1.0 also runs on Intel — arm64 entries in appcast.xml would push an arm64 build to an Intel 0.1.0.
  • Also pass inputs.tag/channel + github.repository to the step via env instead of interpolating ${{ }} into the bash body (shell-injection hardening, per CodeRabbit).

Verification

  • Empirical (Sparkle's prebuilt generate_appcast, basename appcast.xml, no -o): writes local appcast.xml, adds the new entry, preserves a seeded old entry's signature, creates no stray appcast-*.xml.
  • Adversarial review across 4 lenses (CI-correctness, LockIME-parity, 0.1.0-orphan/cross-arch, completeness): 0 confirmed defects.

Docs updated (AGENTS.md, docs/RUNBOOK.md); the -o approach is removed. Rebased onto current main (includes #4).

Note: ci.yml (this PR's checks) builds/tests but does not call build-publish.yml; only the scheduled nightly / manual release dispatch exercise the publish path.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 224610c7-d3ff-4dab-a20b-f3f51ada4fcd

📥 Commits

Reviewing files that changed from the base of the PR and between b164313 and 6e21e3c.

📒 Files selected for processing (4)
  • .github/workflows/build-publish.yml
  • AGENTS.md
  • Sources/CloseUp/Info.plist
  • docs/RUNBOOK.md
✅ Files skipped from review due to trivial changes (1)
  • docs/RUNBOOK.md

Summary by CodeRabbit

  • Bug Fixes
    • Improved the release feed publishing process so arm64 and x86_64 reliably produce and publish correctly named appcast outputs to the matching feed entries.
    • Updated the app’s Sparkle update feed configuration to use the canonical universal appcast.xml baseline, avoiding incorrect per-architecture URL behavior.
  • Documentation
    • Refined publishing/runbook guidance (including architecture instructions) to clarify how feed naming must work during appcast generation and at the gh-pages publish boundary.

Walkthrough

The workflow now generates architecture-specific Sparkle appcast files for arm64 and x86_64, seeds each from the matching gh-pages feed, and publishes those files. The app bundle feed URL is changed back to the canonical appcast.xml, and the docs now describe appcast.xml as the local working filename with per-architecture names applied only at the publish boundary.

Possibly Related PRs

  • oomol-lab/CloseUp#3: Shares the same per-architecture appcast generation and gh-pages publication flow.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required type: subject style and matches the appcast publish fix.
Description check ✅ Passed The description is clearly about the same workflow and Info.plist appcast naming changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/appcast-output-name

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-publish.yml:
- Around line 231-236: The shell step is interpolating workflow inputs directly
in the bash source, so `${{ inputs.tag }}` and `${{ inputs.channel }}` can be
turned into shell syntax before parsing. Move these values into the step’s env
for the script that builds `GA_ARGS`, then read them as quoted shell variables
inside the bash block. Update the references in the download URL prefix and the
beta-channel conditional to use the env-backed variables instead of direct
workflow expressions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7425072c-3930-4380-bd5d-607764d6b8df

📥 Commits

Reviewing files that changed from the base of the PR and between e746d84 and 00acfe2.

📒 Files selected for processing (1)
  • .github/workflows/build-publish.yml

Comment thread .github/workflows/build-publish.yml Outdated
BlackHole1 added a commit that referenced this pull request Jun 30, 2026
…lation)

GitHub Actions expands ${{ }} before bash parses the run script, so
interpolating inputs.tag/inputs.channel (and github.repository) directly into
the body is a shell-injection surface — release.yml's version/tag are free-text
on workflow_dispatch. Pass them through the step env block and read quoted
shell variables instead. Addresses CodeRabbit review on PR #5.
…IME)

The nightly/release "Build appcasts" step exited 1 right after
"Wrote 1 new update ... in appcast-arm64.xml". generate_appcast derives the
output appcast filename from the app's SUFeedURL basename (it can't run the app,
reads Info.plist). Commit #3 set SUFeedURL to .../appcast-arm64.xml, so the tool
wrote appcast-arm64.xml in every build/dist-$ARCH dir while the CI seeds, tests,
and publishes the LOCAL file build/dist-$ARCH/appcast.xml -> test -f failed.

Mirror LockIME instead of forcing a per-arch local name with -o:

- Revert Sources/CloseUp/Info.plist SUFeedURL to .../appcast.xml. It is a runtime
  no-op (UpdaterDelegate.feedURLString pins an explicit per-arch URL for both
  arches), so its only jobs are the generate_appcast naming basis and the 0.1.0
  default. With basename=appcast.xml the tool writes the local appcast.xml the CI
  already expects -- no -o.
- The local working file in each build/dist-$ARCH is always appcast.xml (the arch
  is in the directory name); the per-arch feed name is applied ONLY at the
  gh-pages boundary (seed appcast-$ARCH.xml -> local appcast.xml; publish local
  appcast.xml -> appcast-$ARCH.xml).
- Unlike LockIME (legacy arm64-only, so arm64's feed IS appcast.xml), CloseUp's
  universal 0.1.0 also runs on Intel, so the feeds stay symmetric
  (appcast-arm64.xml / appcast-x86_64.xml) and appcast.xml is a frozen 0.1.0
  orphan the pipeline never writes -- otherwise an Intel 0.1.0 would pull an arm64
  build.

Also pass inputs.tag/channel + github.repository to the step via env instead of
interpolating ${{ }} into the bash body (shell-injection hardening, per CodeRabbit).

Verified with Sparkle's prebuilt generate_appcast: basename=appcast.xml, no -o ->
writes local appcast.xml, adds the new entry, preserves a seeded old entry's
signature, no stray appcast-*.xml.

Docs/AGENTS.md/RUNBOOK updated; the -o approach is removed.
@BlackHole1 BlackHole1 force-pushed the fix/appcast-output-name branch from b164313 to 6e21e3c Compare June 30, 2026 04:05
@BlackHole1 BlackHole1 changed the title ci: pin per-arch appcast output name with generate_appcast -o ci: fix appcast publish by keeping SUFeedURL=appcast.xml (mirror LockIME) Jun 30, 2026
@BlackHole1 BlackHole1 merged commit e8a65f4 into main Jun 30, 2026
3 checks passed
@BlackHole1 BlackHole1 deleted the fix/appcast-output-name branch June 30, 2026 04:12
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