Skip to content

ci(example): un-draft Play release, attach release notes, link install URL, platform-selective triggers#354

Merged
evan-masseau merged 3 commits intorel/2.4.0from
ecm/example-publish-improvements
May 4, 2026
Merged

ci(example): un-draft Play release, attach release notes, link install URL, platform-selective triggers#354
evan-masseau merged 3 commits intorel/2.4.0from
ecm/example-publish-improvements

Conversation

@evan-masseau
Copy link
Copy Markdown
Contributor

@evan-masseau evan-masseau commented May 1, 2026

Description

Targeted improvements to the example app's Play Store + TestFlight publish workflow now that the listing is mature enough for non-draft submissions, plus tighter trigger granularity so we can publish one platform at a time when needed.

Due Diligence

  • I have tested this on a simulator/emulator or a physical device, on iOS and Android (if applicable).
  • I have added sufficient unit/integration tests of my changes.
  • I have adjusted or added new test cases to team test docs, if applicable.
  • I am confident these changes are implemented with feature parity across iOS and Android (if applicable).

Note on iOS feature parity: TestFlight side stays unchanged for the install-link / release-notes parts because xcrun altool (the Apple uploader we use) doesn't emit an install URL — there's no symmetric link to surface in Slack. Release notes for TestFlight ("What to Test") would require a separate API call we don't currently make. Out of scope for this PR. Trigger-selectivity is symmetric across both platforms.

Release/Versioning Considerations

  • Patch Contains internal changes or backwards-compatible bug fixes.
  • Minor Contains changes to the public API.
  • Major Contains breaking changes.
  • Contains readme or migration guide changes.
  • This is planned work for an upcoming release.

CI-only change, no SDK API surface affected.

Changelog / Code Overview

1. status: draftstatus: completed

The listing now has active builds on internal and closed test tracks, so the per-app "Set up your app" requirements are satisfied. Non-draft submissions on the internal track now go live for testers automatically instead of sitting in the Play Console as drafts waiting for manual promotion.

2. Release notes from GitHub release body

r0adkll/upload-google-play@v1.1.3 accepts a whatsNewDirectory containing whatsnew-<locale> files. On release: published events, the workflow writes ${{ github.event.release.body }} (truncated to Play's 500-char per-locale cap, character-aware via bash parameter expansion to avoid splitting multi-byte UTF-8 — caught by Cursor Bugbot, see reply) to ${RUNNER_TEMP}/whatsnew/whatsnew-en-US and passes the dir to the upload action. Other triggers (manual dispatch, push to master, labeled PR) skip the prep step and the build lands without notes — those builds aren't user-facing releases anyway.

3. Install URL in Slack notification

Reading the upload action's source (edits.ts:97–99), the internalSharingDownloadUrl output is emitted for every non-internalsharing track, not just for the internalsharing track as the action's action.yml docstring suggests. The URL format is https://play.google.com/apps/test/<package>/<versionCode> and is only resolvable by users already authorized for the build (no enrollment leak), making it safe to post to a public Slack channel.

The Deploy step now has id: play_upload, the success-notification step passes install_url: ${{ steps.play_upload.outputs.internalSharingDownloadUrl }}, and the notify-slack-publish composite action gained an optional install_url input that conditionally renders an Install: <url> line in the existing details section.

4. Platform-selective triggers

Today the workflow is all-or-nothing — every trigger publishes both Android and iOS. New behavior:

Trigger Behavior
workflow_dispatch New platform input dropdown: both (default) / android / ios
pull_request labeled deploy-example-app Both platforms (existing behavior preserved)
pull_request labeled deploy-example-app:android Android only
pull_request labeled deploy-example-app:ios iOS only
release: published Both platforms (unchanged)
push to master Both platforms (unchanged)

The cleanup-label job widened to remove whichever variant was applied (startsWith('deploy-example-app') filter, label name pulled from event payload via env var so dynamic).

⚠️ Repo-settings task: The new deploy-example-app:android and deploy-example-app:ios labels need to be created in the repo's Issues → Labels page before they can be applied to PRs. GitHub auto-creates labels for some flows but pull_request: labeled triggers require pre-existing labels.

Test Plan

  • YAML parses cleanly (verified via python3 -c 'import yaml; yaml.safe_load(...)').
  • Bash parameter expansion verified character-aware locally (hé€ll → 5 chars / 8 bytes, no mid-codepoint cut).
  • Trigger the publish workflow via workflow_dispatch against this branch with platform: android, confirm only the Android job runs.
  • Same with platform: ios, confirm only the iOS job runs.
  • Same with platform: both, confirm both jobs run (regression check on the default path).
  • Apply the deploy-example-app:android label to a test PR, confirm only the Android job runs and the label gets removed afterward.
  • Confirm the existing deploy-example-app (umbrella) label still triggers both jobs (regression check).
  • On the next 2.4.0 GitHub release, confirm the release body shows up as the Play Store internal-track release notes (and that the 500-char truncation behaves on a long body with emojis).
  • Confirm the Slack message renders with the new Install: line and the URL opens correctly for an enrolled tester.

Related Issues/Tickets

Follow-up to MAGE-452 (Release RN v2.4.0). Depends on #353 merging first since this branches from ecm/bump-version's tip — once #353 lands on rel/2.4.0, this diff against rel/2.4.0 reduces to just the four changes above.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default mode and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 031775a. Configure here.

Comment thread .github/workflows/publish-example.yml Outdated
evan-masseau added a commit that referenced this pull request May 1, 2026
`head -c 500` truncates by byte, not character. If the GitHub release
body has multi-byte UTF-8 (emojis, accented text) right at the
boundary, the byte-based cut can land mid-codepoint and produce
invalid UTF-8 that the Play Store API may reject.

Switch to bash parameter expansion `${RELEASE_BODY:0:500}`, which is
locale-aware (ubuntu-24.04 defaults to en_US.UTF-8) and counts whole
characters. Per Google's docs the per-locale cap is 500 characters
anyway, so character-based truncation is also semantically correct.

Reported by Cursor Bugbot on PR #354.
@evan-masseau evan-masseau changed the title ci(example): un-draft Play release, attach release notes, link install URL ci(example): un-draft Play release, attach release notes, link install URL, platform-selective triggers May 1, 2026
@evan-masseau evan-masseau added the deploy-example-app:android Deploy the android example app to play store internal test track label May 1, 2026
@github-actions github-actions Bot removed the deploy-example-app:android Deploy the android example app to play store internal test track label May 1, 2026
@evan-masseau evan-masseau marked this pull request as ready for review May 4, 2026 14:17
@evan-masseau evan-masseau requested a review from a team as a code owner May 4, 2026 14:17
@klaviyoit klaviyoit requested a review from ndurell May 4, 2026 14:17
…l URL in Slack

- `status: draft` -> `completed`. Listing has active builds on internal
  and closed test tracks, so non-draft submissions are now accepted.
- On `release: published`, write the GitHub release body to a
  `whatsnew-en-US` file (truncated to Play's 500-char per-locale cap)
  and pass `whatsNewDirectory` so the upload action attaches release
  notes. Other triggers (manual / push / labeled PR) skip this and the
  build lands without notes.
- Capture `internalSharingDownloadUrl` from the upload action — it's
  emitted for every non-internalsharing track, not just `internalsharing`
  itself, despite what the action's docstring suggests. Pass into the
  Slack notify action via a new `install_url` input that conditionally
  renders an `Install: <url>` line. Only resolvable by users already
  authorized for the build, so safe to ship in a public-channel message.
- TestFlight side stays without an install link — `xcrun altool`
  doesn't emit one.
`head -c 500` truncates by byte, not character. If the GitHub release
body has multi-byte UTF-8 (emojis, accented text) right at the
boundary, the byte-based cut can land mid-codepoint and produce
invalid UTF-8 that the Play Store API may reject.

Switch to bash parameter expansion `${RELEASE_BODY:0:500}`, which is
locale-aware (ubuntu-24.04 defaults to en_US.UTF-8) and counts whole
characters. Per Google's docs the per-locale cap is 500 characters
anyway, so character-based truncation is also semantically correct.

Reported by Cursor Bugbot on PR #354.
Lets us trigger Android-only or iOS-only publishes when the other
platform's job isn't relevant (e.g. iOS-only signing experiment, Android
keystore rotation).

- `workflow_dispatch` gains a `platform` input (`both` / `android` /
  `ios`, default `both`) — surfaces as a dropdown in the GitHub Actions
  "Run workflow" dialog.
- `pull_request: labeled` now recognizes three labels:
  - `deploy-example-app`         → both (existing behavior preserved)
  - `deploy-example-app:android` → Android only
  - `deploy-example-app:ios`     → iOS only
- `release: published` and `push` to master keep their existing "both
  platforms always run" behavior.
- cleanup-label job widened to remove whichever variant was applied
  (`startsWith` filter, label name pulled from the event payload via env).

Note: the new `:android` / `:ios` labels need to be created in the repo
settings before they can be applied to PRs. GitHub auto-creates labels
on first use in some flows but not for `pull_request: labeled` triggers.
@evan-masseau evan-masseau force-pushed the ecm/example-publish-improvements branch from f70ef00 to f04997a Compare May 4, 2026 14:29
@ndurell
Copy link
Copy Markdown
Contributor

ndurell commented May 4, 2026

Solid CI improvement. A couple of non-blocking observations:

whatsNewDirectory on non-release triggers: When the trigger isn't release: published, WHATSNEW_DIR is never set, so ${{ env.WHATSNEW_DIR }} passes an empty string to the upload action. Assuming r0adkll/upload-google-play handles an empty whatsNewDirectory gracefully (no notes attached) — that matches the intended behavior per the PR description, just worth a quick sanity check that the action doesn't error on an empty/unset value.

cleanup-label with platform-selective jobs: When only Android is triggered via deploy-example-app:android, the deploy-ios job is skipped. A skipped job in needs does satisfy always() in GHA, so the label cleanup will correctly run — just a non-obvious behavior worth noting for future maintainers.

Otherwise looks great — the startsWith filter for label cleanup is a clean improvement, the UTF-8 truncation fix is solid, and the platform selectivity is well-structured.

@evan-masseau evan-masseau merged commit fce281d into rel/2.4.0 May 4, 2026
14 checks passed
@evan-masseau evan-masseau deleted the ecm/example-publish-improvements branch May 4, 2026 14:49
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.

3 participants