Skip to content

ci(ios): publish tagged releases as binary targets via Buildkite#502

Draft
jkmassel wants to merge 1 commit into
trunkfrom
jkmassel/drop-committed-js-build
Draft

ci(ios): publish tagged releases as binary targets via Buildkite#502
jkmassel wants to merge 1 commit into
trunkfrom
jkmassel/drop-committed-js-build

Conversation

@jkmassel
Copy link
Copy Markdown
Contributor

@jkmassel jkmassel commented May 11, 2026

Summary

  • bin/release.sh stops at "bump versions on trunk and push" — no more git tag, no more gh release create.
  • A new :rocket: Publish Swift release $NEW_VERSION Buildkite step, gated on build.env("NEW_VERSION") != null, takes over: builds + signs the XCFramework, uploads to S3, rewrites Package.swift to .release(version:, checksum:), tags, and creates the GitHub Release.
  • Mirrors the wordpress-rs tag-release flow (release/validate/update_swift_package/publish_release_to_github lanes; tag's commit lives off trunk, only the tag ref is pushed).

Why

Tagged releases currently ship Package.swift in .local mode, so SPM consumers (WordPress-iOS pins v0.15.0) resolve the JS bundle from ios/Sources/GutenbergKitResources/Gutenberg/ — which is why those 61 files are still committed despite #495 wiring up XCFramework distribution for PR builds.

Once a tag's Package.swift points at the prebuilt XCFramework on CDN (this PR), and WordPress-iOS bumps to a tag cut under the new flow, the committed iOS bundle and the two commented-out lines at .gitignore:200-202 can finally be dropped.

How a release works after this

Step 1 — local (same as today, minus the tag/release):

make release VERSION_TYPE=patch

Bumps package.json / GutenbergKitVersion.swift / GutenbergKitVersion.kt, runs make build, commits as chore(release): X.Y.Z, pushes to trunk. Done.

Step 2 — Buildkite:

  1. Open https://buildkite.com/automattic/gutenbergkit/builds/new
  2. Branch: trunk
  3. Environment Variables: NEW_VERSION=vX.Y.Z

The new :rocket: step:

  1. Validates the tag/release doesn't already exist (git_tag_exists + get_github_release).
  2. Rewrites Package.swift to .release(version: "vX.Y.Z", checksum: ...) (reusing the rewrite_resources_mode! helper from ci(ios): publish + prune per-PR XCFramework snapshot branches #495).
  3. Uploads the XCFramework to s3://a8c-apps-public-artifacts/gutenbergkit/vX.Y.Z/.
  4. Checks out a local release/vX.Y.Z branch, commits the rewrite, tags vX.Y.Z, pushes only the tag (push_git_tags, not the branch).
  5. gh release create vX.Y.Z --generate-notes with the XCFramework + checksum as assets. Adds --prerelease when the version contains -.

The tag's commit is parented on the release commit but unreachable from trunk's history — same shape as the pr-build/<n> and (deferred) trunk-build snapshot branches, just published under a tag ref instead of a branch ref.

Changes

Fastfile

Pipeline

  • .buildkite/pipeline.yml: New :rocket: Publish Swift release $NEW_VERSION step, gated on build.env("NEW_VERSION") != null. Existing :s3: Publish XCFramework to S3 step also gated on NEW_VERSION == null so the two don't double-upload.
  • .buildkite/release.sh (new): Sources use-bot-for-git, downloads the xcframework + checksum artifacts from build-xcframework, runs bundle exec fastlane release version:$NEW_VERSION.

Release script

  • bin/release.sh: Dropped create_tag, create_github_release, is_prerelease (unused), and the gh dependency check. Push is now git push origin trunk (no --tags). New print_publish_instructions prints the Buildkite trigger steps after the trunk push.

Behavior change: prereleases now get a GitHub Release

Previously, bin/release.sh skipped gh release create for prereleases (anything with a - suffix) — the tag was pushed but no GH Release existed. The new :rocket: flow does create a GH Release for prereleases, marked with --prerelease. This is intentional: every tag now has a corresponding Release page with the XCFramework + checksum attached, and consumers who previously pinned prerelease tags via Git revision can keep doing so.

Docs

  • docs/releases.md: Rewrote into a Step 1 / Step 2 flow.
  • docs/wordpress-app-integration.md: Updated two stale "make release creates the tag/GH release" lines.

What's left for the JS bundle cleanup

  • Cut a tag through the new flow (e.g. v0.16.0) and confirm consumers resolve the binary target.
  • WordPress-iOS bumps to that tag.
  • Uncomment .gitignore:200-202 and git rm the 61 files under ios/Sources/GutenbergKitResources/Gutenberg/.

Test plan

Most of this can only be exercised end-to-end by cutting an actual release, so most checkboxes won't flip until then.

Pipeline-only checks (pre-merge)

  • A regular trunk push (no NEW_VERSION) hits the existing :s3: step and uploads under gutenbergkit/<commit-sha>/, same as today.
  • A regular trunk push does not trigger the new :rocket: step.
  • A PR push hits Publish PR XCFramework, not the new :rocket: step.

Release dry-run (against a throwaway version)

  • Kick off a Buildkite build on trunk with NEW_VERSION=v0.0.0-test.0. Confirm:
    • :rocket: Publish Swift release v0.0.0-test.0 step runs.
    • S3 has the xcframework at gutenbergkit/v0.0.0-test.0/.
    • Tag v0.0.0-test.0 is created on the remote.
    • The tag's Package.swift:9 reads .release(version: "v0.0.0-test.0", checksum: ...).
    • GH Release v0.0.0-test.0 is created with --prerelease and the xcframework attached.
    • No release/v0.0.0-test.0 branch is pushed to the remote.
    • The existing :s3: step is skipped on the same build.
  • Pull the tag into a scratch SPM consumer. swift package resolve downloads the binary artifact from CDN; checksum validates.
  • Re-run the same Buildkite build → validate lane fails fast because the tag already exists.

Cleanup after dry-run

  • Delete the test tag, GH Release, and S3 artifacts.

Related

Mirrors the wordpress-rs tag-release flow. `bin/release.sh` stops at
bumping versions on trunk; a follow-up Buildkite build kicked off with
`NEW_VERSION=v<x.y.z>` then rewrites `Package.swift` to
`.release(version:, checksum:)`, tags, and creates the GitHub Release.

The tag's commit lives off trunk (parented on the release commit but
only reachable via the tag ref), so SPM consumers pinning the tag
resolve the prebuilt XCFramework from CDN rather than rebuilding from
the local source bundle.

This is the precondition for ignoring the committed iOS JS bundle at
`ios/Sources/GutenbergKitResources/Gutenberg/` — once a tagged release
exists in `.release(...)` mode and WordPress-iOS bumps to it, those
files can be dropped from trunk.
@github-actions github-actions Bot added the [Type] Build Tooling Issues or PRs related to build tooling label May 11, 2026
@wpmobilebot
Copy link
Copy Markdown

XCFramework Build

This PR's XCFramework is available for testing. Add the following to your Package.swift:

.package(url: "https://github.com/wordpress-mobile/GutenbergKit", branch: "pr-build/502")

Built from d8c20ad

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Build Tooling Issues or PRs related to build tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants