Integrations
fastlane plugin
If you already ship with fastlane, the plugin folds Pharen's whole release step into one call. It derives everything it needs from your lane context and the built artifacts — you configure nothing in the lane itself.
Install
fastlane add_plugin pharenOne-time prerequisites, per repo:
- the
pharenCLI on yourPATH—npm install -g @pharen-ai/cli(the plugin is a thin wrapper over it; see the CLI reference). Plugin 0.2.0 needs@pharen-ai/cli0.1.0 or later; - a committed
.pharen.ymlat the repo root (org:andapp:— no secrets); - a credential the CLI can use — see Credentials.
Credentials
The plugin never prints a credential or puts one in a command line, and passes none on except a GitLab job's ID tokens (below) — the CLI finds its own, in this order: PHAREN_AUTH_TOKEN when it is exported (a CI secret), then a CI job's own identity once an organization owner has bound that pipeline (no secret at all), then the session pharen auth login stored on your machine. The CLI reference covers each.
On GitHub Actions, each pharen command asks GitHub for a fresh ID token, so a bound job needs nothing more. A GitLab ID token signs in once, and pharen_release runs three pharen commands, so a GitLab job declares one token per command and the plugin hands each command the next:
beta:
id_tokens:
PHAREN_ID_TOKEN_1: { aud: 'https://api.pharen.ai' }
PHAREN_ID_TOKEN_2: { aud: 'https://api.pharen.ai' }
PHAREN_ID_TOKEN_3: { aud: 'https://api.pharen.ai' }
script:
- bundle exec fastlane betapharen_release spends three (two when there are no dSYMs to upload, or none could be prepared, and strict is false), and pharen_upload_build and pharen_upload_symbols one each, so count every action the lane calls. The plugin reads the tokens when fastlane loads it and takes them out of the environment, a lone PHAREN_ID_TOKEN included, so no other action or build step inherits one; each command gets its token in its own environment, and none is printed. pharen_release checks the count before it runs anything and fails the lane when the job is short, or when it declares a single PHAREN_ID_TOKEN instead, rather than registering the release and then being refused at the upload; with strict: false it warns and skips all three steps. An exported PHAREN_AUTH_TOKEN takes precedence, and the tokens go unspent.
The whole integration
Call pharen_release right after build_app:
lane :beta do
build_app(scheme: "MyApp")
pharen_release
endWith no arguments, pharen_release finds the IPA and dSYMs in the lane context, reads the version, build number, and bundle id from the IPA's own Info.plist, and takes the commit sha from git. It then registers the release, uploads every dSYM the archive produced, uploads the build, prints the OTA install link, and returns it — also in lane_context[SharedValues::PHAREN_INSTALL_URL].
À la carte
Prefer to run the steps separately? Two more actions, both zero-arg after a build:
pharen_upload_symbols # dSYMs from the lane context
pharen_upload_symbols(dsym_paths: ["build/MyApp.dSYM"]) # or explicit
pharen_upload_build # IPA from the lane context → install linkTestFlight and the App Store
pharen_release is for tester builds: it always uploads the build for an install link. In a store lane, upload the dSYMs before the build leaves:
lane :release do
build_app(scheme: "MyApp", export_method: "app-store")
pharen_upload_symbols
upload_to_testflight
endFailure posture
The default is strict: if a step errors, the lane fails. A build shipped without its symbols produces crashes that stay unreadable until they arrive, so the plugin stops rather than letting that pass unnoticed.
Pass strict: false (or set PHAREN_STRICT=false) in lanes where a Pharen step must never be the reason a build fails; then any step's error is logged as a loud warning and the lane continues. PHAREN_STRICT takes true or false (also yes/no, on/off, each in lowercase or all caps); any other value, an empty one included, fails the lane rather than being guessed at. Unset it to take the default.
A missing dSYM is never quiet: it fails a strict lane and warns loudly in any other. When no dSYM is found, a dSYM path does not exist, or a zip holds no dSYM, a strict pharen_release stops before it registers or uploads anything. Re-runs are safe — the server deduplicates symbols by debug id, and the underlying commands exit cleanly when everything is already present.
Options
pharen_release
| Option | Env | Default | Description |
|---|---|---|---|
ipa | PHAREN_IPA | lane context | Path to the .ipa. Defaults to what gym / build_app left behind. |
dsym_paths | PHAREN_DSYM_PATHS | lane context | dSYM bundles or zips to upload. Defaults to gym's output plus any download_dsyms results. |
pharen_binary | PHAREN_BINARY | pharen | Command that invokes the CLI (may include arguments, e.g. npx --yes @pharen-ai/cli). |
strict | PHAREN_STRICT | true | Fail the lane on any step's error. false warns and continues instead. |
Returns the install-link string once the build uploads, even if registration or the symbols step failed with strict: false, and sets PHAREN_INSTALL_URL. It returns nil when there is no IPA, its Info.plist cannot be read, or the build upload fails (with strict: false).
pharen_upload_build
| Option | Env | Default | Description |
|---|---|---|---|
ipa | PHAREN_IPA | lane context | Path to the .ipa. Defaults to the lane context. |
pharen_binary | PHAREN_BINARY | pharen | Command that invokes the CLI. |
strict | PHAREN_STRICT | true | Fail the lane on error. false warns and continues instead. |
pharen_upload_symbols
| Option | Env | Default | Description |
|---|---|---|---|
dsym_paths | PHAREN_DSYM_PATHS | lane context | dSYM inputs — .dSYM bundles, dSYM .zip files, or raw DWARF binaries. |
pharen_binary | PHAREN_BINARY | pharen | Command that invokes the CLI. |
strict | PHAREN_STRICT | true | Fail the lane on error. false warns and continues instead. |