Here is a template that includes deployment to three environments, slack notifications, and build # incrementing.
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
######################################################
# Some example usages:
# - fastlane test
# - fastlane test environment:"LIVE"
# - fastlane deploy
# - fastlane deploy environment:"LIVE"
# - fastlane deploy environment:"LIVE" importCerts:true
# - fastlane deploy disableNotification:true
# - fastlane increment
# - fastlane increment environment:"LIVE"
######################################################
default_platform :ios
platform :ios do
######################################################
# Settings
######################################################
SLACK_DEVELOP_URL = "https://hooks.slack.com/...." # Hook for developer notification
SLACK_DEPLOY_URL = "https://hooks.slack.com/...." # Hook for deployment notification
SLACK_MESSAGE = "A new AppName build was deployed to TestFlight! Processing has started..."
SLACK_USERNAME = "fastlane"
SLACK_ICON = "https://www.example.com/myapp.jpg"
SLACK_BUILD_NUMBER_PLIST = "./AppName/AppName/Info.plist"
APPSTORE_CONNECT_DEV = "https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app/12345/testflight?section=iosbuilds"
APPSTORE_CONNECT_TEST = "https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app/12345/testflight?section=iosbuilds"
APPSTORE_CONNECT_LIVE = "https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app/12345/testflight?section=iosbuilds"
KEYCHAIN_PATH = "/Users/buildserveruser/Library/Keychains/login.keychain"
KEYCHAIN_PASSWORD = "blabla"
CERTS_GIT_BRANCH = "master"
CERTS_GIT_USERNAME = "certs@example.com"
CERTS_GIT_APP_IDENTIFIERS = ["de.company.appname.dev", "de.company.appname.dev.widget1", "de.company.appname.dev.widget2", "de.company.appname.test", "de.company.appname.test.widget1", "de.company.appname.test.widget2", "de.company.appname", "de.company.appname.widget1", "de.company.appname.widget2"]
CERTS_GIT_TYPE = "appstore"
# Plist files for build increment
APP_PLIST_FILES = {
"LIVE"=>["./AppName/AppName/Info.plist", "./AppName/Widget 1/Info.plist", "./AppName/Widget 2/Info.plist"],
"TEST"=>["./AppName/AppName/AppName Test.plist", "./AppName/Widget 1/Widget 1-Test.plist", "./AppName/Widget 2/Widget 2 Test-Info.plist"],
"DEV"=>["./AppName/AppName Dev.plist", "./AppName/Widget 1/Widget 1-Dev.plist", "./AppName/Widget 2/Widget 2 Dev-Info.plist"]
}
######################################################
# Private lanes
######################################################
##################################
# Import certificates
private_lane :importCerts do
unlock_keychain(path: KEYCHAIN_PATH, password: KEYCHAIN_PASSWORD)
match(git_branch: CERTS_GIT_BRANCH, username: CERTS_GIT_USERNAME, app_identifier: CERTS_GIT_APP_IDENTIFIERS, type: CERTS_GIT_TYPE, readonly: true)
end
##################################
# Build number incrementation
# - paths: Paths to the plist file
private_lane :incrementBuildNumber do |options|
for path in options[:paths]
new_build_number = get_info_plist_value(path: path, key: "CFBundleVersion").to_i + 1
set_info_plist_value(path: path, key: "CFBundleVersion", value: new_build_number.to_s)
end
end
##################################
# Slack notification lane
# - environment: Option can be DEV, TEST, or LIVE. Defaults to DEV.
private_lane :notifySlack do |options|
# Which environment?
if options[:environment] == "DEV"
connect_link = APPSTORE_CONNECT_DEV
environment_name = "Develop"
elsif options[:environment] == "TEST"
connect_link = APPSTORE_CONNECT_TEST
environment_name = "Test"
elsif options[:environment] == "LIVE"
connect_link = APPSTORE_CONNECT_LIVE
environment_name = "Live"
else
puts "[WARNING] Failed to find environment " + options[:environment]
next
end
# Notify slack
commit = last_git_commit
short_hash = commit[:abbreviated_commit_hash]
build_number = get_info_plist_value(path: SLACK_BUILD_NUMBER_PLIST, key: "CFBundleVersion")
slack(message: SLACK_MESSAGE, username: SLACK_USERNAME, icon_url: SLACK_ICON, payload: {
"App Store Connect" => connect_link,
"Build" => build_number,
"Environment" => environment_name,
"Git version" => short_hash,
}, default_payloads: [], fail_on_error: false, slack_url: SLACK_DEPLOY_URL)
end
######################################################
# Public lanes
######################################################
##################################
# Clean the project
desc "Clean the project for all environments"
lane :clean do
xcclean
clear_derived_data
end
##################################
# Increment build count
# - environment: Option can be ALL, DEV, TEST, or LIVE. Defaults to ALL.
desc "Increment build count, by default for ALL environments"
lane :increment do |options|
# Default to ALL
if !options[:environment] || options[:environment] == "ALL"
incrementBuildNumber paths:APP_PLIST_FILES["DEV"]
incrementBuildNumber paths:APP_PLIST_FILES["TEST"]
incrementBuildNumber paths:APP_PLIST_FILES["LIVE"]
else
incrementBuildNumber paths:APP_PLIST_FILES[options[:environment]]
end
end
##################################
# Deployment (test, build, deploy)
# - environment: Option can be DEV, TEST, or LIVE. Defaults to DEV.
# - importCerts: A true or false option whether or not to do fastlane match before building. Defaults to false.
# - disableNotification: A true or false option to disable notifications to Slack
desc "Deploy project to TestFlight, by default DEV environment"
lane :deploy do |options|
# Do I need to import certificates?
if options[:importCerts]
importCerts
end
# Which environment to build?
environmentForNotification = options[:environment]
if options[:environment] == "LIVE"
scan(workspace: "AppName.xcworkspace", scheme: "AppName Live", clean: false, slack_url: SLACK_DEVELOP_URL, slack_only_on_failure: true)
gym(workspace: "AppName.xcworkspace", scheme: "AppName Live", export_method: "app-store", output_directory: "./build/fastlane/", output_name: "AppName-Live.ipa")
elsif options[:environment] == "TEST"
scan(workspace: "AppName.xcworkspace", scheme: "AppName Test", clean: false, slack_url: SLACK_DEVELOP_URL, slack_only_on_failure: true)
gym(workspace: "AppName.xcworkspace", scheme: "AppName Test", export_method: "app-store", output_directory: "./build/fastlane/", output_name: "AppName-Test.ipa")
else
environmentForNotification = "DEV"
scan(workspace: "AppName.xcworkspace", scheme: "AppName Dev", clean: false, slack_url: SLACK_DEVELOP_URL, slack_only_on_failure: true)
gym(workspace: "AppName.xcworkspace", scheme: "AppName Dev", export_method: "app-store", output_directory: "./build/fastlane/", output_name: "AppName-Dev.ipa")
end
# Deploy
pilot(skip_waiting_for_build_processing: true)
# Switch to notify slack lane
if options[:disableNotification]
notifySlack environment:environmentForNotification
end
end
##################################
# Run unit tests
# - environment: Option can be DEV, TEST, or LIVE. Defaults to DEV.
desc "Run unit tests, by default DEV environment"
lane :test do |options|
# Do I need to import certificates?
if options[:importCerts]
importCerts
end
# Which environment to test?
if options[:environment] == "LIVE"
scan(workspace: "AppName.xcworkspace", scheme: "AppName Live", clean: false, slack_url: SLACK_DEVELOP_URL, slack_only_on_failure: true)
elsif options[:environment] == "TEST"
scan(workspace: "AppName.xcworkspace", scheme: "AppName Test", clean: false, slack_url: SLACK_DEVELOP_URL, slack_only_on_failure: true)
else
scan(workspace: "AppName.xcworkspace", scheme: "AppName Dev", clean: false, slack_url: SLACK_DEVELOP_URL, slack_only_on_failure: true)
end
end
end
# For more information about the Appfile, see:
# https://docs.fastlane.tools/advanced/#appfile
for_platform :ios do
# iOS specific
apple_dev_portal_id "user@example.com" # Apple Developer Account
itunes_connect_id "user@example.com" # App Store Connect Account
team_id "ABCD1234" # Developer Portal Team ID
itc_team_id "ABCD1234" # App Store Connect Team ID
# Development
for_lane :buildDev do
app_identifier 'de.company.appname.dev'
end
for_lane :deployDev do
app_identifier 'de.company.appname.dev'
end
# Test
for_lane :buildTest do
app_identifier 'de.company.appname.test'
end
for_lane :deployTest do
app_identifier 'de.company.appname.test'
end
# Live
for_lane :buildLive do
app_identifier 'de.company.appname'
end
for_lane :deployLive do
app_identifier 'de.company.appname'
end
end
git_url "git@gitlab.com:company/iOS-Certificates.git"