Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150# aesthetic computer (iOS) — App Store submission driven by an App Store# Connect API key. Same shape as apple/oskiewar and slab/menuband, for the# same reasons: one lane per irreversible step, screenshots owned by exactly# one lane, and nothing submits for review until `ship` is asked for by name.## fastlane ios meta / shots / build / upload / privacy / ship## The record already exists (id 6450940883, live as 1.0 since 2023-07-04), so# there is no `create` lane. The version and build number that land in App# Store Connect come from the Xcode project (MARKETING_VERSION and# CURRENT_PROJECT_VERSION on both targets — the iMessage extension has to# match the app), not from this file. VERSION and BUILD_NUMBER below only say# which App Store version the metadata and ship lanes address, so keep them# in step with the project when you bump it.require "shellwords" # the signing key's path reaches xcodebuild as an argumentAPI_KEY_ID = "S4TQKG6U99" # Admin role — required for cloud signing.API_ISSUER = "69a6de78-fa3c-47e3-e053-5b8c7c11a4d1"API_KEY_PATH = File.expand_path("~/.appstoreconnect/private_keys/AuthKey_S4TQKG6U99.p8")BUNDLE = "aesthetic.computer"TEAM = "FB5948YR3S"VERSION = ENV.fetch("AC_IOS_VERSION", "1.2")BUILD_NUMBER = ENV.fetch("AC_IOS_BUILD_NUMBER", "5")# Everything is anchored to this Fastfile's own location so the lanes resolve# no matter where fastlane is invoked from.APPLE_DIR = File.expand_path("..", __dir__)PROJECT = File.join(APPLE_DIR, "aesthetic.computer.xcodeproj")SCHEME = "aesthetic.computer"# One path, written by `build` and read by `upload`. They must never disagree# — an `upload` lane pointed at a directory nobody exports to is a lane that# fails the first time anyone runs it.# Override for a one-off export: AC_IOS_IPA=build/export-1.2/aesthetic.computer.ipaIPA = File.expand_path(ENV.fetch("AC_IOS_IPA", "build/export/aesthetic.computer.ipa"), APPLE_DIR)# The last mile is Menu Band's. asc.mjs attaches the newest VALID build and# opens the review submission idempotently, and refuses while a build is still# processing. deliver's own submit path died with "No data" for Menu Band, so# it is not trusted with the submission here either.ASC = File.expand_path("../slab/menuband/bin/asc.mjs", APPLE_DIR)PRIVACY_JSON = File.join(__dir__, "app_privacy_details.json")# Without these three, -allowProvisioningUpdates has no credentials to mint a# certificate with and falls back to whatever is already in the keychain,# which on a fresh machine is nothing.AUTH_XCARGS = "-allowProvisioningUpdates " \ "-authenticationKeyPath #{API_KEY_PATH.shellescape} " \ "-authenticationKeyID #{API_KEY_ID} " \ "-authenticationKeyIssuerID #{API_ISSUER}"def asc_key app_store_connect_api_key( key_id: API_KEY_ID, issuer_id: API_ISSUER, key_filepath: API_KEY_PATH, in_house: false, )end# Every deliver call in this file agrees on these: never guess at a review# submission, never let precheck's guideline scan gate an upload, and always# overwrite rather than fail on an existing draft.def deliver_defaults { api_key: asc_key, platform: "ios", app_identifier: BUNDLE, submit_for_review: false, force: true, run_precheck_before_submit: false, # deliver validates these directories on EVERY call, even with the # matching skip_* flag set, and rejects the platform subfolder as an # unknown locale — so the platform-specific paths live here, not per lane. metadata_path: "./fastlane/metadata/ios", screenshots_path: "./fastlane/screenshots/ios", }endplatform :ios do # 1. Metadata only. Creates the App Store version when it does not exist # yet. Safe to re-run. lane :meta do deliver(**deliver_defaults, app_version: VERSION, skip_screenshots: true, skip_binary_upload: true) end # 1b. Screenshots have one owner. Two deliver actions racing the same # version leave byte-identical duplicates in App Store Connect. lane :shots do deliver(**deliver_defaults, app_version: VERSION, skip_metadata: true, skip_binary_upload: true, overwrite_screenshots: true) end # 2. Archive and export an App Store .ipa. Signing is automatic and # cloud-issued: -allowProvisioningUpdates plus an Admin API key lets # xcodebuild mint the Apple Distribution certificate and the App Store # profiles for both the app and the iMessage extension without anyone # opening the portal. The same credentials go to the export step, which # is where the re-signing actually happens. lane :build do # A device archive needs the iPhoneOS SDK, not an installed simulator. sdk = sh("xcrun --sdk iphoneos --show-sdk-path", log: false).strip UI.user_error!("Xcode has no iPhoneOS SDK installed") unless File.directory?(sdk) build_ios_app( project: PROJECT, scheme: SCHEME, configuration: "Release", export_method: "app-store", export_team_id: TEAM, xcargs: AUTH_XCARGS, export_xcargs: AUTH_XCARGS, output_directory: File.dirname(IPA), output_name: File.basename(IPA, ".ipa"), ) end # 3. Upload that .ipa and nothing else, which starts App Store processing. lane :upload do UI.user_error!("no ipa at #{IPA} — run `fastlane ios build` first") unless File.exist?(IPA) deliver(**deliver_defaults, ipa: IPA, skip_metadata: true, skip_screenshots: true) end # 3b. Publish the App Privacy nutrition label. The public API has no # appDataUsages endpoint, so this drives Apple's private routes with the # same key. Only once the JSON exists and agrees with what the binary # really does. lane :privacy do UI.user_error!("author #{PRIVACY_JSON} first — apple/oskiewar/fastlane/app_privacy_details.json is the shape") unless File.exist?(PRIVACY_JSON) upload_app_privacy_details( api_key: asc_key, app_identifier: BUNDLE, json_path: PRIVACY_JSON, ) end # 4. Submit for review: attach the newest processed build to VERSION and # open the review submission. Irreversible, so it only runs by name. lane :ship do sh("node", ASC, "submit", VERSION, "--app", "aestheticcomputer", "--platform", "IOS") endend