Skip to content

feat(cli): fastlane APNs key setup on spaceship - #1995

Merged
ArnabChatterjee20k merged 5 commits into
messaging-provider-cli-apns-adaptersfrom
messaging-provider-cli-apns-adapter-fastlane
Oct 9, 2026
Merged

ArnabChatterjee20k merged 5 commits into
messaging-provider-cli-apns-adaptersfrom
messaging-provider-cli-apns-adapter-fastlane

Conversation

@ArnabChatterjee20k

@ArnabChatterjee20k ArnabChatterjee20k commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Stacked on #1992 (the APNs key setup adapters). This is the fastlane adapter, built on spaceship, fastlane's open-source (MIT) Apple Developer portal client. spaceship is the most actively maintained of the three implementations, which makes it a good fallback when Apple changes its API.

What

internal/apns/fastlane: an apns.Adapter named fastlane that creates the key with the fastlane the person already has installed.

appwrite init apns --create-key --provider fastlane
# or
APPWRITE_APNS_SETUP=fastlane appwrite init apns --create-key

How

  • The lane: a Fastfile with one lane, create_apns_key, is embedded with go:embed. On each run it's written to fastlane/Fastfile in a private temp folder and run there with fastlane create_apns_key out:… name:… environment:… [team_id:…]. The CLI ships no Ruby; it uses the fastlane already installed:
    • Bundler: when the Gemfile in the folder the CLI runs in, or in its ios/ folder (Flutter and React Native keep it there), lists fastlane and bundle is installed, it runs bundle exec fastlane with BUNDLE_GEMFILE set to that Gemfile, so the project's pinned fastlane runs from the temp folder.
    • Otherwise: fastlane from PATH (a gem or Homebrew installation).
  • Requirements: fastlane 2.225.0 or later. Its release notes (21 October 2024) call it "a required fix for authenticating with Apple via Apple ID": the first spaceship with SRP sign-in, without which Apple answers 503. A missing or older fastlane returns apns.ErrUnavailable before anything is sent to Apple, with fastlane update_fastlane advice.
  • Credentials: the adapter asks for the Apple ID and password through the CLI's prompts when the request has none (APPWRITE_APPLE_ID / APPWRITE_APPLE_PASSWORD answer them), and passes them as FASTLANE_USER / FASTLANE_PASSWORD, so fastlane's credentials manager never offers to store them in the Keychain.
  • Terminal: spaceship asks for the two-factor code, and for a team when the account has several, on the terminal. Its own session cache (~/.fastlane/spaceship/) skips two-factor on later runs.
  • The lane's steps:
    1. Spaceship::Portal.login
    2. select_team(team_id:), or picks the only team or asks
    3. client.create_key! with { scope: 'team', environment: <requested> } for the APNs service
    4. client.download_key
  • Environment: Key.create hard-codes environment: 'all', so the lane calls the client directly to honour --environment.
  • Errors:
    • "maximum allowed number of Keys" becomes apns.MaxKeysError with the team's keys from list_keys.
    • Spaceship::InvalidUserCredentialsError becomes apns.ErrInvalidCredentials.
    • Anything else comes back as spaceship's message.
  • Result: fastlane logs to stdout, so the lane writes it as JSON to a 0600 file named by out:.
  • Environment variables: FASTLANE_SKIP_UPDATE_CHECK, FASTLANE_OPT_OUT_USAGE and FASTLANE_HIDE_CHANGELOG keep fastlane from checking for updates, sending usage data or printing changelogs during the run.

Tests

  • Version parsing from fastlane --version output, including the multi-line installation banner, and the 2.225.0 minimum.
  • Result decoding: key, full team, invalid credentials, failure, empty.
  • With a stand-in fastlane:
    • the Fastfile is in place
    • the lane gets out:, name:, environment: and team_id:
    • the Apple ID and password are asked when missing and passed through the environment, and not asked when the request has them
    • an old or missing fastlane is refused without running the lane
  • Bundler: finding a Gemfile that lists fastlane (project root or ios/), ignoring one that doesn't, and running bundle exec fastlane with BUNDLE_GEMFILE through a stand-in bundle.
  • ruby -c on the Fastfile.

Not yet verified

A real run against Apple with fastlane installed, which wasn't possible on the machine this was written on. The spaceship calls used (login, select_team, client.create_key!, client.list_keys, client.download_key, client.team_id) were checked against spaceship's current source.

Note

Like #1993 and #1994, this adds one line to apnsAdapters(). Once all three are merged it reads apns.NewRegistry(appwrite.New(), expo.New(), fastlane.New()).

The fastlane adapter creates APNs keys with spaceship, fastlane's
open-source Apple Developer portal client, through the fastlane the
person already has installed: a lane in an embedded Fastfile runs in a
private temp folder, so a gem, Homebrew or bundler installation all work
and no Ruby ships with the CLI. It needs fastlane 2.226.0 or later, the
first to sign in with SRP, and reports apns.ErrUnavailable otherwise.

The adapter asks for the Apple ID and password when the request has
none and passes them as FASTLANE_USER and FASTLANE_PASSWORD, so fastlane
never offers to store them in the Keychain; spaceship asks for the
two-factor code on the terminal. The lane calls create_key! directly so
the requested environment is honoured (Key.create always asks for all),
maps InvalidUserCredentialsError to apns.ErrInvalidCredentials and a
full team to apns.MaxKeysError with the team's keys.
Registers the fastlane adapter, picked with --provider fastlane or
APPWRITE_APNS_SETUP=fastlane.
2.225.0 (October 2024) is the release that added SRP sign-in, per its
notes: earlier versions get 503 from Apple. The minimum was set one
release too high.
@hansi-codes

hansi-codes Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

The previously reported Bundler fallback issue is fixed, and the incremental changes introduce no additional defects.

Adds a fastlane APNs key setup adapter to the CLI, embedding a Fastfile that uses spaceship to create and download keys. It supports project Bundler installations, validates the installed fastlane version, and maps lane results and errors into the APNs adapter contract. The CLI registers the adapter and includes tests for its setup and execution paths.

Latest changes: The newest commits make the adapter return ErrUnavailable instead of falling back to a global fastlane when the project pins fastlane but Bundler is unavailable, and add a test for that case.

Verdict New comments Fixed Still open
✅ Approved 0 1 0
📂 Walkthrough · 5
File Change
src/SDK/Language/CLI.php Registers the fastlane adapter, test file, and embedded Fastfile in the generated CLI.
templates/cli/internal/apns/fastlane/adapter.go Runs the embedded spaceship lane, selects project Bundler when configured, validates fastlane, and maps results to APNs keys and errors.
templates/cli/internal/apns/fastlane/adapter_test.go Covers fastlane version and result parsing, credentials, lane execution, Bundler selection, and unavailable Bundler behavior.
templates/cli/internal/apns/fastlane/helper/Fastfile Defines the lane for signing in, selecting a team, creating an APNs key, and writing its result.
templates/cli/internal/cmd/initpush.go Adds fastlane to the CLI's APNs adapter registry.
✅ Fixed since the last review · 1
  • Don't silently bypass a detected Bundler fastlane · templates/cli/internal/apns/fastlane/adapter.go:216

Reviewed the commits since 5dfc509 · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes 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.

🔵 Tier A · See the inline comments. Summary

Comment thread templates/cli/internal/apns/fastlane/adapter.go Outdated
The fastlane setup ran fastlane from PATH in a temporary folder, so a
fastlane installed only through a project's Gemfile was reported as
unavailable. When the Gemfile in the folder the CLI runs in, or in its
ios folder as Flutter and React Native projects keep it, lists fastlane
and bundle is installed, the lane now runs with bundle exec fastlane and
BUNDLE_GEMFILE pointing at that Gemfile. Otherwise fastlane from PATH is
used as before. A Bundler fastlane that does not start asks for bundle
install.

@hansi-codes hansi-codes 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.

🔵 Tier A · See the inline comments. Summary

Comment thread templates/cli/internal/apns/fastlane/adapter.go Outdated
When the project's Gemfile lists fastlane but Bundler is missing, the
fastlane setup fell back to fastlane from PATH, which can be a different
version from the pinned one. It now reports apns.ErrUnavailable naming
the Gemfile and how to install Bundler.

@hansi-codes hansi-codes 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.

🟢 Tier S · Looks good to merge. Summary

@ArnabChatterjee20k
ArnabChatterjee20k merged commit 53d63b3 into messaging-provider-cli-apns-adapters Oct 9, 2026
54 of 61 checks passed
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