digitalfabrik/integreat-app

View on GitHub
native/fastlane/Fastfile

Summary

Maintainability
Test Coverage
fastlane_version "2.220.0"

require_relative "read_build_config"

require "yaml"
require "base64"

# Google API fails randomly, try to retry
# https://github.com/fastlane/fastlane/issues/21507#issuecomment-1723116829
ENV['SUPPLY_UPLOAD_MAX_RETRIES']='5'

# The following parameters have to be passed:
# path: The path of the artifact (apk or ipa) to upload (relative to home dir)
desc "Upload the artifact to BrowserStack Live"
lane :browserstack_upload_live do |options|
  ensure_env_vars(
    env_vars: ["BROWSERSTACK_USERNAME", "BROWSERSTACK_ACCESS_KEY"]
  )

  path = options[:path]

  if [path].include?(nil)
    raise "'nil' passed as parameter! Aborting..."
  end

  upload_to_browserstack_app_live(
    browserstack_username: ENV["BROWSERSTACK_USERNAME"],
    browserstack_access_key: ENV["BROWSERSTACK_ACCESS_KEY"],
    file_path: "#{ENV['HOME']}/#{path}"
  )
end

platform :android do
  # The following parameters have to be passed:
  # apk_path: The path of the apk to upload (relative to home dir)
  desc "Upload the APK and run E2E tests on BrowserStack"
  lane :browserstack_e2e_tests do |options|
    ensure_env_vars(
        env_vars: ["BROWSERSTACK_USERNAME", "BROWSERSTACK_ACCESS_KEY"]
    )

    apk_path = options[:apk_path]

    if [apk_path].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    upload_to_browserstack_app_automate(
        browserstack_username: ENV["BROWSERSTACK_USERNAME"],
        browserstack_access_key: ENV["BROWSERSTACK_ACCESS_KEY"],
        file_path: "#{ENV['HOME']}/#{apk_path}"
    )

    ENV["E2E_CONFIG"] = "android"
    ENV["E2E_BROWSERSTACK_USER"] = ENV["BROWSERSTACK_USERNAME"]
    ENV["E2E_BROWSERSTACK_KEY"] = ENV["BROWSERSTACK_ACCESS_KEY"]
    ENV["E2E_BROWSERSTACK_APP"] = lane_context[SharedValues::BROWSERSTACK_APP_ID]

    yarn(
        command: "test:e2e",
        package_path: "package.json"
    )
  end

  # The following parameters have to be passed:
  # version_code: The version code of the app
  # version_name: The version name of the app
  # build_config_name: The name of the build config
  # aab_path: The path of the aab to upload (relative to home dir)
  # production_delivery: Whether the aab should be uploaded to the production track
  desc "Deliver the app to Play Store. Depending on the option `production_delivery` the update is released to the general public."
  lane :playstore_upload do |options|
    ensure_env_vars(
        env_vars: ["GOOGLE_SERVICE_ACCOUNT_JSON"]
    )

    version_code = options[:version_code]
    version_name = options[:version_name]
    build_config_name = options[:build_config_name]
    aab_path = options[:aab_path]
    production_delivery = options[:production_delivery]

    if [version_name, version_code, build_config_name, aab_path, production_delivery].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    build_config = read_build_config(build_config_name, 'android')
    skip_images = build_config_name != "integreat"
    track = production_delivery === true ? "production" : "beta"

    puts("delivering #{build_config_name} v#{version_name} to track #{track}")

    # https://docs.fastlane.tools/actions/supply/
    upload_to_play_store(
        version_code: version_code,
        version_name: version_name,
        package_name: build_config['applicationId'],
        metadata_path: "./android/fastlane/#{build_config_name}/metadata",
        track: track,
        skip_upload_changelogs: false,
        skip_upload_images: skip_images,
        skip_upload_screenshots: skip_images,
        skip_upload_metadata: false,
        release_status: "completed",
        aab: "#{ENV['HOME']}/#{aab_path}",
        json_key_data: ENV["GOOGLE_SERVICE_ACCOUNT_JSON"]
    )
  end

  # The following parameters have to be passed:
  # build_config_name: The name of the build config
  desc "Promote the most recent version in the beta track to the production track in the Play Store."
  lane :playstore_promote do |options|
    ensure_env_vars(
      env_vars: ["GOOGLE_SERVICE_ACCOUNT_JSON"]
    )

    build_config_name = options[:build_config_name]

    if [build_config_name].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    build_config = read_build_config(build_config_name, 'android')
    application_id = build_config['applicationId']

    production_version_codes = google_play_track_version_codes(
      track: "production",
      package_name: application_id,
      json_key_data: ENV["GOOGLE_SERVICE_ACCOUNT_JSON"]
    )
    beta_version_codes = google_play_track_version_codes(
      track: "beta",
      package_name: application_id,
      json_key_data: ENV["GOOGLE_SERVICE_ACCOUNT_JSON"]
    )

    if beta_version_codes.length == 0 || beta_version_codes[0] <= production_version_codes[0]
      puts("Nothing to do, latest version already available in production track...")
      next
    end

    puts("promoting #{build_config_name} v#{beta_version_codes[0]} to production track")

    # https://docs.fastlane.tools/actions/supply/
    upload_to_play_store(
      version_code: beta_version_codes[0],
      package_name: application_id,
      track: "beta",
      track_promote_to: "production",
      skip_upload_changelogs: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
      skip_upload_metadata: true,
      skip_upload_apk: true,
      skip_upload_aab: true,
      release_status: "completed",
      json_key_data: ENV["GOOGLE_SERVICE_ACCOUNT_JSON"]
    )
  end
end

platform :ios do
  private_lane :apple_auth do |options|
    ensure_env_vars(
        env_vars: ["APP_STORE_CONNECT_API_KEY_ID", "APP_STORE_CONNECT_API_ISSUER_ID", "APP_STORE_CONNECT_API_KEY_CONTENT"]
    )

    app_store_connect_api_key(
      key_id: ENV['APP_STORE_CONNECT_API_KEY_ID'],
      issuer_id: ENV['APP_STORE_CONNECT_API_ISSUER_ID'],
      key_content: Base64.decode64(ENV['APP_STORE_CONNECT_API_KEY_CONTENT'])
    )
  end

  # The following parameters have to be passed:
  # build_config_name: The name of the build config
  # ipa_path: The path of the ipa to upload (relative to home dir)
  desc "Upload the IPA and run E2E tests on BrowserStack"
  lane :browserstack_e2e_tests do |options|
    ensure_env_vars(
        env_vars: ["BROWSERSTACK_USERNAME", "BROWSERSTACK_ACCESS_KEY"]
    )

    ipa_path = options[:ipa_path]

    if [ipa_path].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    upload_to_browserstack_app_automate(
        browserstack_username: ENV["BROWSERSTACK_USERNAME"],
        browserstack_access_key: ENV["BROWSERSTACK_ACCESS_KEY"],
        file_path: "#{ENV['HOME']}/#{ipa_path}"
    )

    ENV["E2E_CONFIG"] = "ios"
    ENV["E2E_BROWSERSTACK_USER"] = ENV["BROWSERSTACK_USERNAME"]
    ENV["E2E_BROWSERSTACK_KEY"] = ENV["BROWSERSTACK_ACCESS_KEY"]
    ENV["E2E_BROWSERSTACK_APP"] = lane_context[SharedValues::BROWSERSTACK_APP_ID]
    yarn(
        command: "test:e2e",
        package_path: "package.json"
    )
  end

  # The following parameters have to be passed:
  # version_name: The version name of the app
  # build_config_name: The name of the build config
  # ipa_path: The path of the ipa to upload (relative to home dir)
  desc "Deliver the app to App Store Connect. The app is submitted for review and released automatically."
  lane :appstoreconnect_upload do |options|
    apple_auth()

    version_name = options[:version_name]
    ipa_path = options[:ipa_path]
    build_config_name = options[:build_config_name]

    if [version_name, ipa_path, build_config_name].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    skip_screenshots = build_config_name != "integreat"

    puts("delivering #{build_config_name} v#{version_name}")
    puts("skip_screenshots: #{skip_screenshots}")

    # https://docs.fastlane.tools/actions/deliver/
    deliver(
        ipa: "#{ENV['HOME']}/#{ipa_path}",
        app_version: version_name,
        submit_for_review: true,
        automatic_release: true,
        force: true,
        skip_screenshots: skip_screenshots,
        skip_metadata: false,
        overwrite_screenshots: true,
        skip_app_version_update: false,
        metadata_path: "./ios/fastlane/#{build_config_name}/metadata",
        screenshots_path: "./ios/fastlane/#{build_config_name}/screenshots",
        precheck_include_in_app_purchases: false, # We do not have inapp purchases
        submission_information: { add_id_info_uses_idfa: false }  # https://firebase.google.com/docs/analytics/configure-data-collection?platform=ios
                                                                  # https://support.google.com/firebase/answer/6318039?hl=en
    )
  end

  # The following parameters have to be passed:
  # build_config_name: The name of the build config
  # ipa_path: The path of the ipa to upload (relative to home dir)
  desc "Deliver the app to TestFlight for testers"
  lane :testflight_upload do |options|
    apple_auth()

    build_config_name = options[:build_config_name]
    ipa_path = options[:ipa_path]

    if [build_config_name, ipa_path].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    build_config = read_build_config(build_config_name, 'ios')
    apple_id = build_config['appleId']

    # https://docs.fastlane.tools/actions/upload_to_testflight/
    upload_to_testflight(
        skip_waiting_for_build_processing: true,
        apple_id: apple_id,
        ipa: "#{ENV['HOME']}/#{ipa_path}",
        distribute_external: false
    )
  end

  # The following parameters have to be passed:
  # build_config_name: The name of the build config
  desc "Promote the app from testflight to production in App Store Connect."
  lane :appstoreconnect_promote do |options|
    apple_auth()

    build_config_name = options[:build_config_name]

    if [build_config_name].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    build_config = read_build_config(build_config_name, 'ios')
    bundle_identifier = build_config['bundleIdentifier']
    skip_screenshots = build_config_name != "integreat"

    testflight_build_number = latest_testflight_build_number(app_identifier: bundle_identifier)
    testflight_version = lane_context[SharedValues::LATEST_TESTFLIGHT_VERSION]
    app_store_build_number = app_store_build_number(app_identifier: bundle_identifier)

    if testflight_build_number <= app_store_build_number
      puts("Nothing to do, latest version already available in app store connect...")
      next
    end

    puts("promoting #{build_config_name} v#{testflight_version} - #{testflight_build_number} to app store connect")
    puts("skip_screenshots: #{skip_screenshots}")

    prepare_metadata(version_name: testflight_version, build_config_name: build_config_name)

    # https://docs.fastlane.tools/actions/deliver/#submit-build
    deliver(
      app_version: testflight_version,
      build_number: testflight_build_number.to_s,
      app_identifier: bundle_identifier,
      submit_for_review: true,
      automatic_release: true,
      force: true,
      skip_metadata: false,
      skip_screenshots: skip_screenshots,
      overwrite_screenshots: true,
      skip_binary_upload: true,
      metadata_path: "./ios/fastlane/#{build_config_name}/metadata",
      screenshots_path: "./ios/fastlane/#{build_config_name}/screenshots",
      precheck_include_in_app_purchases: false, # We do not have inapp purchases
      submission_information: { add_id_info_uses_idfa: false }  # https://firebase.google.com/docs/analytics/configure-data-collection?platform=ios
                                                                # https://support.google.com/firebase/answer/6318039?hl=en
    )
  end

  # The following parameters have to be passed:
  # build_config_name: The name of the build config
  # version_name: The version name of the release notes to prepare
  desc "Prepare metadata"
  lane :prepare_metadata do |options|
    build_config_name = options[:build_config_name]
    version_name = options[:version_name]

    if [build_config_name, version_name].include?(nil)
      raise "'nil' passed as parameter! Aborting..."
    end

    `yarn --cwd ../../tools manage-metadata prepare-metadata #{build_config_name} appstore --override-version-name #{version_name}`
  end

end