Files
pleno-vue/fastlane/Fastfile
T
Jeppe B 5702d45bc6 fix(ios): harden App Store release automation (#221)
## Summary

- replace the unsupported top-level App Store version collection with
Apple's app-scoped version endpoint
- add tested release-policy and availability readback for exact
version/build, `AFTER_APPROVAL`, Denmark only, no preorder, and no
automatic future territories
- strengthen the stable `App Store Readiness` check and align
Fastlane/candidate handoff with the approved 1.0.0 release policy

## Task contract

`truckwash-ios-release-20260723` — R4 (`ci-policy`, `release-policy`,
`credential-handling`, `branch-protection-or-rules`,
`mobile-store-submission`). The user explicitly approved implementation,
protected-master delivery, and the App Store release path.

## Changed files

- App Store Connect client and dependency-free Node tests
- App Store readiness and candidate workflows
- Fastlane candidate release configuration
- Apple App Store release runbook

## Verification

- `node --test tests/node/app-store-connect.test.mjs` — 10 passed
- `node scripts/mobile/validate-app-store.mjs --strict` — passed
- `node scripts/mobile/check-permissions.mjs` — passed
- App Store product-readiness Vitest — 5 passed
- ESLint on changed Node files — passed
- workflow YAML parsing — passed
- `git diff --check` — passed
- local Fastlane validation unavailable because Ruby/Bundler is not
installed on this host; `App Store Readiness` runs it on GitHub

## Release target

- iOS App Store
- bundle `io.truckwash.app`
- version `1.0.0`
- App Store Connect app `6792777794`
- Denmark only
- automatic release after approval
- no preorder or phased release for 1.0.0

The repository App Store automation switch remains disabled until this
change is merged and credential health is reverified.
2026-07-23 12:59:17 +00:00

56 lines
1.8 KiB
Ruby

default_platform(:ios)
def app_store_api_key
issuer_id = ENV["APP_STORE_CONNECT_ISSUER_ID"].to_s.strip
app_store_connect_api_key(
key_id: ENV.fetch("APP_STORE_CONNECT_API_KEY_ID"),
issuer_id: issuer_id.empty? ? nil : issuer_id,
key_content: ENV.fetch("APP_STORE_CONNECT_API_PRIVATE_KEY_BASE64"),
is_key_content_base64: true,
duration: 1200,
in_house: false
)
end
platform :ios do
desc "Validate and upload the signed IPA, then wait for App Store Connect processing"
lane :upload_internal do
api_key = app_store_api_key
upload_to_testflight(
api_key: api_key,
app_identifier: ENV.fetch("IOS_BUNDLE_ID"),
ipa: ENV.fetch("IOS_IPA_PATH"),
changelog: ENV.fetch("TESTFLIGHT_WHAT_TO_TEST", "Automatisk intern build fra verificeret master."),
distribute_external: false,
notify_external_testers: false,
skip_submission: true,
skip_waiting_for_build_processing: false,
wait_processing_interval: 30,
reject_build_waiting_for_review: false
)
end
desc "Create/update the Denmark App Store candidate without submitting it for review"
lane :prepare_candidate do
api_key = app_store_api_key
deliver(
api_key: api_key,
app_identifier: ENV.fetch("IOS_BUNDLE_ID"),
app_version: ENV.fetch("IOS_MARKETING_VERSION"),
build_number: ENV.fetch("IOS_BUILD_NUMBER"),
metadata_path: "fastlane/metadata",
screenshots_path: "fastlane/screenshots",
skip_binary_upload: true,
skip_metadata: false,
skip_screenshots: false,
overwrite_screenshots: true,
force: true,
submit_for_review: false,
automatic_release: true,
phased_release: false,
run_precheck_before_submit: false,
precheck_include_in_app_purchases: false
)
end
end