Newer
Older
DummyAnd / fastlane / Fastfile
# Customise this file, documentation can be found here:
# https://github.com/fastlane/fastlane/tree/master/fastlane/docs
# All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md
# can also be listed using the `fastlane actions` command

# Change the syntax highlighting to Ruby
# All lines starting with a # are ignored when running `fastlane`

# If you want to automatically update fastlane if a new version is available:
# update_fastlane

# This is the minimum version number required.
# Update this, if you use features of a newer version
fastlane_version "2.144.0"

default_platform :android

platform :android do

  # Extract Application Id from gradle file
  def get_application_id(flavor = nil, path = '../app/build.gradle', constant_name = 'applicationId')
    application_id = nil
    application_id_suffix = nil
    toggle_flavors = false
    current_flavor = nil
    unless File.file?(path)
      UI.message(" -> No file exists at path: (#{path})!")
      return application_id
    end
    begin
      file = File.new(path, 'r')
      while (line = file.gets)
        next unless line.include? constant_name
        components = line.strip.split(' ')
        application_id = components[components.length - 1].tr("\"", '')
        UI.message("#{constant_name} = #{application_id}")
        break
      end
      if flavor
        file.each do |line|
          if line[/^\s*([#\/].*)?$/]
            next
          end
          #UI.message("Line = #{line.tr("\n",'')}")
          if toggle_flavors
            current_flavor = line[/(?=\s*)\w+(?=\s+\{)/]
            if ! current_flavor
              break
            end 
            #UI.message("Flavor = #{current_flavor}")
            toggle_flavors = false
            next
          end
          if current_flavor == flavor and line.include? "#{constant_name}Suffix"
            components = line.strip.split(' ')
            application_id_suffix = components[components.length - 1].tr("\"", '')
            UI.message("#{constant_name}Suffix = #{application_id_suffix}")
            next
          end
          if line[/\s*}/]
            if current_flavor
              current_flavor = nil
              toggle_flavors = true
              next
            end
            if toggle_flavors
              break
            end
            next
          end
          if line[/(?=\s*)productFlavors(?=\s+\{)/]
            toggle_flavors = true
            next
          end
        end
      end
      file.close
    rescue => err
      UI.error("An exception occurred while reading the gradle file: #{err}")
      err
    end
    return "#{application_id}#{application_id_suffix}"
  end

  # Define flavor name for deploy branch
  def getFlavorName(options)
    flavor = nil
    if options and options[:fl_branch] and ! options[:fl_branch][/.*_.*/]
      # Use option if provided
      flavor = options[:fl_branch]
    else
      # Fallback on environment variable if any
      if ENV['BRANCH_NAME'] and ! ENV['BRANCH_NAME'][/.*_.*/]
        flavor = ENV['BRANCH_NAME']
      end
    end
    if flavor == 'master'
      flavor = 'production'
    end
    if flavor == nil or flavor == ''  
      # Choose default flavor
      flavor = 'dev2'
    end
    return flavor
  end

  # Define package name for a branch
  def getPackageName(options = nil)
    return get_application_id(getFlavorName(options))
  end

  # Extract version_name from environment var named VERSION
  def getVersionName(options = nil)
    version_name = ENV['VERSION'] ? ENV['VERSION'].split('-')[0] : nil
    return version_name
  end

  # Extract version_code from environment var named VERSION
  def getVersionCode(options = nil)
    version_code = ENV['VERSION'] ? ENV['VERSION'].split('-')[1] : nil
    return version_code
  end

  before_all do |lane, options|
    # This block is called before any lane
  end

  desc "Display infos about the app"
  lane :info do |options|
    UI.message("App version name = #{getVersionName()}")
    UI.message("App version number = #{getVersionCode()}")
    UI.message("App Flavor = #{getFlavorName(options)}")
    UI.message("App ID = #{getPackageName(options)}")
  end

  desc "Validate the current setup"
  # For now, dry-run gradle task
  # TODO: verify Android SDK
  lane :validate do |options|
    gradle(
      task: "clean assemble",
      build_type: 'Release',
      flavor: "#{getFlavorName(options)}",
      flags: "--dry-run",
    )
  end

  desc "Run all the tests"
  # Test both acceptance and production flavors
  # So we detect problem for those before releasing
  # Test for dev2 will be done with build lane anyway
  lane :test do |options|
    gradle(
      task: "test",
      build_type: 'Release',
      flavor: "production",
    )
    gradle(
      task: "test",
      build_type: 'Release',
      flavor: "acceptance",
    )
  end

  desc "Run integration tests"
  # Test remote API
  # So we know this build will not work againt the back-end
  lane :intgtest do |options|
    gradle(
      task: "networking:test"
    )
  end

  desc "Build the apk or the bundle depending of the environment"
  lane :build do |options|
    build_task = ENV['ANDROID_BUNDLE'] == 'true' ? 'bundle' : 'assemble'
    gradle(
      task: "clean #{build_task}",
      build_type: 'Release',
      flavor: "#{getFlavorName(options)}",
    )
  end

  desc "Update metadata only, including images and screenshots"
  lane :deploy_metadata do |options|
    supply(
      skip_upload_aab: true,
      skip_upload_apk: true,
      skip_upload_metadata: false,
      skip_upload_images: false,
      skip_upload_screenshots: false,
    )
  end

  desc "Submit a new build to Firebase App Distribution"
  lane :firebase do |options|
    # Like for alpha and beta, this lane requires the apk to be already available
    firebase_groups = ENV['FIREBASE_GROUPS'] || 'dev'
    firebase_api_token = ENV['FIREBASE_API_TOKEN']
    if ! firebase_api_token
      UI.user_error!("No Firebase API token found in environment (FIREBASE_API_TOKEN)")
    else
      find_firebase_app_id(
        app_identifier: get_application_id(getFlavorName(options)),
      )
      firebase_app_distribution(
        app: lane_context[SharedValues::GOOGLE_APP_ID],
        apk_path: "app/build/outputs/apk/#{getFlavorName(options)}/release/app-#{getFlavorName(options)}-release.apk",
        firebase_cli_token: firebase_api_token,
        release_notes_file: 'fastlane/metadata/android/en-US/changelogs/latest.txt',
        groups: firebase_groups,
      )
    end
  end

  desc "Deploy a new internal version to the Google Play"
  lane :internal do |options|
    # Define general options
    options = {
      :track                    => 'internal',
      :mapping                  => "app/build/outputs/mapping/#{getFlavorName(options)}Release/mapping.txt",
      :skip_upload_metadata     => false,
      :skip_upload_images       => false,
      :skip_upload_screenshots  => false,
      :package_name             => "#{getPackageName(options)}",
    }

    # Add specific options for bundle or apk
    if ENV['ANDROID_BUNDLE'] == 'true'
      options[:aab] = "app/build/outputs/bundle/#{getFlavorName(options)}Release/app-#{getFlavorName(options)}-release.aab"
      options[:skip_upload_aab] = false
    else
      options[:apk] = "app/build/outputs/apk/#{getFlavorName(options)}/release/app-#{getFlavorName(options)}-release.apk"
      options[:skip_upload_apk] = false
    end 

    # Call supply with the final options
    supply(options)
  end

  desc "Deploy a new alpha version to the Google Play"
  lane :alpha do |options|
    supply(
      track: 'internal',
      track_promote_to: 'alpha',
      skip_upload_aab: true,
      skip_upload_apk: true,
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
      package_name: "#{getPackageName(options)}",
      version_code: getVersionCode(),
    )
  end

  desc "Deploy a new beta version to the Google Play"
  lane :beta do |options|
    supply(
      track: 'alpha',
      track_promote_to: 'beta',
      skip_upload_aab: true,
      skip_upload_apk: true,
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
      package_name: "#{getPackageName(options)}",
      version_code: getVersionCode(),
    )
  end

  desc "Deploy a new version to the Google Play"
  lane :production do |options|
    supply(
      track: 'beta',
      track_promote_to: 'production',
      skip_upload_aab: true,
      skip_upload_apk: true,
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
      package_name: "#{getPackageName(options)}",
      version_code: getVersionCode(),
    )
  end

  after_all do |lane, options|
    # This block is called, only if the executed lane was successful
  end

  error do |lane, exception|
    # This block is called, only if the executed lane failed
  end
end


# More information about multiple platforms in fastlane: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
# All available actions: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md

# fastlane reports which actions are used
# No personal data is sent or shared. Learn more at https://github.com/fastlane/enhancer