swift: wire SPM mirror publish (Phase A)#1448
Conversation
Make moq-ffi-v* tags produce a fully consumable Swift Package Manager
release. Three structural fixes plus the publish.sh stub gets wired up:
1. Attach MoqFFI.xcframework.zip to the GitHub release. release-plz has
`git_release_enable = false`, so nothing was creating the GH release
or uploading the xcframework. Added a `release` job in
release-swift.yml that runs `.github/scripts/release.sh create` once
the package job finishes. Without this, the mirror's Package.swift
binaryTarget URL would 404 for every SPM consumer.
2. Tag the mirror with bare semver. The original recipe tagged with
`moq-ffi-v${VERSION}`, which SPM does not recognize as a version.
publish.sh now tags `${VERSION}` (e.g. 0.2.11) on the mirror while
the source monorepo keeps its prefixed tag.
3. Point everything at moq-dev/swift (the newly-created mirror), not
the placeholder moq-dev/moq-swift name the stub was using.
publish.sh additionally:
- Sets a default git identity (overridable via GIT_AUTHOR_NAME/EMAIL).
- Adds --dry-run so the pipeline can be exercised before flipping
PUBLISH_SPM=true. Dry-run uses an anonymous clone, stages the diff,
prints the file list, and exits before any push.
- Filters SWIFT_MIRROR_TOKEN out of git clone stdout/stderr.
- Skips cleanly if the mirror tag already exists (re-run safety).
- Pushes to refs/heads/main explicitly so the very first publish lands
the branch under the expected name regardless of runner default.
- Pushes only the new tag rather than --tags.
package.sh now stages LICENSE-MIT, LICENSE-APACHE, and a minimal
consumer-facing README.md into the mirror tarball so the published
package is properly licensed and a visitor to moq-dev/swift sees an
orientation page rather than a bare manifest.
The `publish` workflow job is still gated on `vars.PUBLISH_SPM`, so
this PR is safe to land without flipping the variable. Once it merges,
the next moq-ffi-v* tag will start attaching the xcframework to the
GH release. After that, a dry-run via `./swift/scripts/publish.sh
--dry-run` against a downloaded artifact confirms the recipe works
end-to-end, and then PUBLISH_SPM + SWIFT_MIRROR_TOKEN can be enabled.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThis pull request adds a release-and-publish workflow for Swift SPM artifacts (new release job, runtime moq-bot token for publishing, and updated publish job), enriches Swift package staging with licenses and a README, implements swift/scripts/publish.sh to mirror staged packages into moq-dev/moq-swift under bare-semver tags (with dry-run support and idempotent tagging), updates Swift README publishing docs, and expands site documentation with new Python, Kotlin, and Swift library pages plus a Libraries navigation grouping. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/release-swift.yml:
- Around line 162-171: Pin mutable Actions to specific SHAs and harden the
checkout step in the release job: replace uses: actions/checkout@v6 with a
pinned SHA (e.g., actions/checkout@<commit-sha>) and uses:
actions/download-artifact@v8 with its pinned SHA, and add persist-credentials:
false to the actions/checkout step in the release job (which runs with contents:
write) to avoid exposing the token; update any related step IDs or names (e.g.,
"Find previous tag" / prev_tag, "Download package") accordingly so the job
continues to reference the same steps.
In `@swift/README.md`:
- Line 65: Replace the incorrect workflow job name "publish-spm" in the README
sentence with the actual workflow identifier and/or display name used in the
repo (use "publish" and/or "Publish to Swift Package mirror") so the runbook
references the real job; update the text that currently reads "The `publish-spm`
job runs `publish.sh`..." to instead reference `publish` (or the human-friendly
"Publish to Swift Package mirror") to avoid confusion.
🪄 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: 2c905fa4-c0b0-4dc8-a339-e195e7233b2d
📒 Files selected for processing (5)
.github/workflows/release-swift.ymlswift/Package.swiftswift/README.mdswift/scripts/package.shswift/scripts/publish.sh
- release-swift.yml: set persist-credentials: false on the release job's checkout. The job has contents: write, but no git operation here uses the stored credential (the gh CLI reads GH_TOKEN env directly), so the token has no business sitting in .git/config. - swift/README.md: the job is named 'publish' / 'Publish to Swift Package mirror', not 'publish-spm'. Fix the runbook reference. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three changes carried in together since they're all part of the same "get SPM publishing usable" stream: 1. Workflow: swap secrets.SWIFT_MIRROR_TOKEN for a moq-bot App token. actions/create-github-app-token@v3 mints a fresh contents:write token scoped to moq-dev/moq-swift on every run, expires in an hour, never at rest. Reuses APP_ID / APP_PRIVATE_KEY already in place for release-rs.yml. No new secret to provision. The publish step also sets GIT_AUTHOR_NAME/EMAIL to moq-bot so the mirror's commit log reflects who pushed. 2. Mirror rename: moq-dev/swift -> moq-dev/moq-swift. The new prefix leaves room for moq-dev/web-transport-swift later without colliding in the org namespace. Updated all references in Package.swift, README, scripts, and the workflow. 3. Docs: added a top-level "Libraries" nav dropdown grouping Rust, TypeScript, Python, Swift, and Kotlin. /rs/ and /js/ stay where they are (no URL breakage); /py/, /swift/, /kt/ are new sections, each with a landing page and a per-package doc covering install, quickstart for subscribe/publish, cancellation semantics, and links to source / package registry / Rust counterpart. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
With moq-bot wired up, there's no PAT to provision and no reason to keep the publish step gated. Every moq-ffi-v* tag now publishes to the mirror unconditionally. Dropped the `if: vars.PUBLISH_SPM == 'true'` on the publish job and the matching steps in the README runbook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
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/release-swift.yml:
- Around line 200-207: The GitHub App token step "Generate moq-bot token" (uses:
actions/create-github-app-token@v3, id: token) should be constrained to least
privilege by adding the permission input for repository contents; update that
step to include permission-contents: write so the generated token only has write
access to repository contents rather than inheriting the app installation’s full
permission set.
🪄 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: 2f155c8b-355c-45e9-9d60-789221359218
📒 Files selected for processing (11)
.github/workflows/release-swift.ymldoc/.vitepress/config.tsdoc/kt/index.mddoc/kt/moq.mddoc/py/index.mddoc/py/moq-net.mddoc/swift/index.mddoc/swift/moq.mdswift/README.mdswift/scripts/package.shswift/scripts/publish.sh
✅ Files skipped from review due to trivial changes (7)
- doc/kt/index.md
- doc/py/index.md
- doc/kt/moq.md
- doc/py/moq-net.md
- doc/swift/moq.md
- doc/swift/index.md
- swift/README.md
CodeRabbit pointed out that without an explicit permission-* input, actions/create-github-app-token inherits the full App installation scope. Add permission-contents: write so the minted token only has the access publish.sh actually uses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
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 `@swift/README.md`:
- Line 60: The README statement about dry-run auth is incorrect:
`swift/scripts/publish.sh` always performs an anonymous clone during dry-run so
exporting `SWIFT_MIRROR_TOKEN` has no effect; update the README text around the
BUILD_VERSION example to explicitly say dry-run uses an anonymous clone
unconditionally and that SWIFT_MIRROR_TOKEN is not used (or alternatively
document that to use authenticated clones you must run the non-dry-run flow),
referencing the `swift/scripts/publish.sh` behavior and the `SWIFT_MIRROR_TOKEN`
variable so readers know the current limitation.
🪄 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: 2770f3fc-9833-48d6-8e36-743a01776f78
📒 Files selected for processing (3)
.github/workflows/release-swift.ymlswift/README.mdswift/scripts/publish.sh
The README said dry-runs against a private mirror work if you export SWIFT_MIRROR_TOKEN, but publish.sh hardcoded an anonymous clone for the dry-run path, so that claim was false. Drop the dry-run/non-dry-run branch and just use the token when it's set (anonymous when not). The required-token check earlier in the script still gates the publish path, so non-dry-run behavior is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Phase A of getting Swift Package Manager publishing working against the new moq-dev/swift mirror. Three structural bugs in the existing pipeline plus the
publish.shstub gets a real implementation.What was broken
MoqFFI.xcframework.zipwas never uploaded to a GitHub release..release-plz.tomlhasgit_release_enable = false, so release-plz creates the tag but no release.release-swift.ymlbuilt the xcframework but only kept it as a workflow artifact. Result: the mirror'sPackage.swiftbinaryTargetURL would have 404'd for every SPM consumer.moq-ffi-v${VERSION}. SPM only recognizes bare semver (X.Y.ZorvX.Y.Z) — anything prefixed is invisible.moq-dev/moq-swift) instead of the actual mirror (moq-dev/swift).What this PR does
releasejob inrelease-swift.ymlthat runs.github/scripts/release.sh createafter the package job and attachesMoqFFI.xcframework.zip+ the staged Swift package tarball to themoq-ffi-v*release. Same patternlibmoq.ymlandmoq-relay.ymlalready use.publish.shrewritten with the hardened recipe:0.2.11) while the monorepo keepsmoq-ffi-v0.2.11.GIT_AUTHOR_NAME/GIT_AUTHOR_EMAILoverridable).--dry-runflag that uses an anonymous clone, stages the diff, and skips commit/push. Lets us exercise the pipeline before flippingPUBLISH_SPM.refs/heads/mainso the very first publish lands under the expected branch name regardless of runner config.--tags.package.shnow stagesLICENSE-MIT,LICENSE-APACHE, and a minimal consumer-facingREADME.mdinto the mirror tarball, so the published repo is properly licensed and a visitor sees an orientation page.Package.swiftandswift/README.mdcomments / docs updated to referencemoq-dev/swift.Safe to merge as-is
The
publishjob is still gated onvars.PUBLISH_SPM == 'true'. Merging this PR does not push anything to the mirror. It does start attaching the xcframework to the GH release on the nextmoq-ffi-v*tag, which is necessary regardless of whether SPM publishing is enabled (it's the same artifact a manual xcframework consumer would download).Phase B (next, separate PR)
After the first post-merge
moq-ffi-v*tag attaches the asset to a release, run./swift/scripts/publish.sh --dry-runagainst the downloaded tarball to verify the recipe works end-to-end. Once green:contents: writeonmoq-dev/swift.SWIFT_MIRROR_TOKENsecret andPUBLISH_SPM=truevariable inmoq-dev/moqsettings.Test plan
bash -nsyntax check on both modified scriptsrelease-swift.ymlmoq-ffi-v*tag: verifyMoqFFI.xcframework.ziplands as a release asset and the URL resolvespublish.sh --dry-runagainst the downloaded tarball, verify it clones the mirror, stages the right tree, and prints a sensible diffPUBLISH_SPM=trueand verify a tiny consumer Package.swift canswift package resolveagainstmoq-dev/swift🤖 Generated with Claude Code