This PR contains all the work related to setting up this project as required to implement the [Assignment](https://repo.rock-n-code.com/rock-n-code/deep-linking-assignment/wiki/Assignment) on top, as intended. To summarise this work: - [x] created a new **Xcode** project; - [x] cloned the `Wikipedia` app and inserted it into the **Xcode** project; - [x] created the `Locations` app and also, its `Libraries` package; - [x] created the `Shared` package to share dependencies between the apps; - [x] added a `Makefile` file and implemented some **environment** and **help** commands. Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Reviewed-on: rock-n-code/deep-linking-assignment#1
444 lines
15 KiB
Ruby
444 lines
15 KiB
Ruby
# Customise this file, documentation can be found here:
|
|
# https://github.com/KrauseFx/fastlane/tree/master/docs
|
|
|
|
$:.unshift File.dirname(__FILE__)
|
|
|
|
default_platform :ios
|
|
|
|
configurations_to_test_on_pull = [
|
|
{device: 'iPhone 14 Pro', os: '16.3'},
|
|
{device: 'iPad Pro (12.9-inch) (5th generation)', os: '15.7.1'}
|
|
]
|
|
|
|
def get_devices_by_scheme_from_options(options)
|
|
configs = options[:configurations] || [{device: 'iPhone 14 Pro', os: '16.3'}]
|
|
devices_by_scheme = {}
|
|
configs.each do |options|
|
|
scheme = options[:scheme] || 'Wikipedia'
|
|
device = options[:device] || 'iPhone 14 Pro'
|
|
os = options[:os] || '16.3'
|
|
sim = "#{device} (#{os})"
|
|
devices = devices_by_scheme[scheme] || []
|
|
devices << sim
|
|
devices_by_scheme[scheme] = devices
|
|
end
|
|
return devices_by_scheme
|
|
end
|
|
|
|
|
|
def get_version_number_from_options(options)
|
|
scheme = options[:scheme] || 'Wikipedia'
|
|
config = options[:configuration] || 'Release'
|
|
return get_version_number(target: scheme, configuration: config)
|
|
end
|
|
|
|
def clean_out_reference_images
|
|
UI.header "Step: Clear previous reference images"
|
|
UI.command "FileUtils.rm_rf(Dir.glob('../WikipediaUnitTests/ReferenceImages_64/*'))"
|
|
FileUtils.rm_rf(Dir.glob('../WikipediaUnitTests/ReferenceImages_64/*'))
|
|
end
|
|
|
|
platform :ios do
|
|
before_all do
|
|
# Set project for commit_version_bump, which seems to get confused by projects in other folders
|
|
ENV['FL_BUILD_NUMBER_PROJECT'] = "Wikipedia.xcodeproj"
|
|
ensure_git_status_clean if ENV['FL_ENSURE_CLEAN']
|
|
end
|
|
|
|
desc "Checks out the sha specified in the environment variables or the main branch"
|
|
lane :checkout do
|
|
sha = ENV['SHA']
|
|
if sha != nil
|
|
puts sha
|
|
commit = last_git_commit
|
|
sh "git checkout #{sha}"
|
|
end
|
|
end
|
|
|
|
desc "Runs linting (and eventually static analysis)"
|
|
lane :analyze do
|
|
read_xcversion
|
|
xcodebuild(
|
|
project: "Wikipedia.xcodeproj",
|
|
scheme: "Wikipedia",
|
|
configuration: "Debug",
|
|
sdk: 'iphonesimulator',
|
|
destination: 'platform=iOS Simulator,OS=15.1,name=iPhone 13 Pro',
|
|
analyze: true
|
|
)
|
|
end
|
|
|
|
desc "Runs tests on select platforms for verifying pull requests"
|
|
lane :verify_pull_request do |options|
|
|
verify({configurations: configurations_to_test_on_pull})
|
|
end
|
|
|
|
desc "Reads Xcode version from the .xcversion file and sets it using xcversion()"
|
|
lane :read_xcversion do |options|
|
|
version = `cat ../.xcversion`
|
|
if ENV['GITHUB_ACTIONS']
|
|
# GitHub actions keeps beta versions around that confuse xcversion()
|
|
# Use the absolute path to select the right version instead
|
|
# Remove trailing 0's to match GitHub's naming conventions
|
|
version_name = version.split('.').select { |n| n != '0' }.join('.')
|
|
`sudo xcode-select -s /Applications/Xcode_#{version_name}.app`
|
|
else
|
|
xcversion(version: version)
|
|
end
|
|
end
|
|
|
|
desc "Runs unit tests, generates reports."
|
|
lane :verify do |options|
|
|
slack_message = nil
|
|
if ENV.key?('CIRCLECI')
|
|
url = ENV['CIRCLE_BUILD_URL']
|
|
number = ENV['CIRCLE_BUILD_NUM']
|
|
job = ENV['CIRCLE_JOB']
|
|
slack_message = "<#{url}|CircleCI #{job} ##{number}>"
|
|
end
|
|
devices_by_scheme = get_devices_by_scheme_from_options(options)
|
|
devices_by_scheme.each do |scheme, devices|
|
|
opts = {
|
|
devices: devices,
|
|
scheme: scheme,
|
|
project: 'Wikipedia.xcodeproj',
|
|
configuration: 'Test',
|
|
disable_concurrent_testing: true,
|
|
output_files: "#{scheme}.junit",
|
|
output_types: 'junit',
|
|
slack_message: slack_message
|
|
}
|
|
scan(opts)
|
|
end
|
|
end
|
|
|
|
desc "Records visual tests."
|
|
lane :record_visual_tests do |options|
|
|
read_xcversion
|
|
clean_out_reference_images
|
|
options[:configurations] ||= configurations_to_test
|
|
devices_by_scheme = get_devices_by_scheme_from_options(options)
|
|
devices_by_scheme.each do |scheme, devices|
|
|
opts = {
|
|
devices: devices,
|
|
scheme: scheme,
|
|
disable_concurrent_testing: true,
|
|
project: 'Wikipedia.xcodeproj',
|
|
buildlog_path: './build',
|
|
configuration: 'Test',
|
|
xcargs: "GCC_PREPROCESSOR_DEFINITIONS='\$(value) WMF_VISUAL_TEST_RECORD_MODE=1'",
|
|
fail_build: false,
|
|
output_types: ''
|
|
}
|
|
scan(opts)
|
|
end
|
|
end
|
|
|
|
desc "Set the build number"
|
|
lane :set_build_number do |options|
|
|
build = options[:build] || 0
|
|
increment_build_number({
|
|
build_number: build
|
|
})
|
|
end
|
|
|
|
desc "Set version number"
|
|
lane :set_version_number do |options|
|
|
increment_version_number(
|
|
version_number: options[:version_number]
|
|
)
|
|
end
|
|
|
|
desc "Increment the app version patch"
|
|
lane :bump_patch do
|
|
increment_version_number(
|
|
bump_type: "patch"
|
|
)
|
|
end
|
|
|
|
desc "Increment the app version minor"
|
|
lane :bump_minor do
|
|
increment_version_number(
|
|
bump_type: "minor"
|
|
)
|
|
end
|
|
|
|
desc "Increment the app version major"
|
|
lane :bump_major do
|
|
increment_version_number(
|
|
bump_type: "major"
|
|
)
|
|
end
|
|
|
|
desc "Change version number and create PR with changes"
|
|
lane :change_version do |options|
|
|
|
|
ensure_git_status_clean(show_diff: true)
|
|
|
|
size = options[:size]
|
|
branch = "fastlane_version_bump"
|
|
case size
|
|
when "patch"
|
|
bump_patch()
|
|
when "minor"
|
|
bump_minor()
|
|
when "major"
|
|
bump_major()
|
|
end
|
|
|
|
commit_version_bump(message: "Version bump")
|
|
push_to_git_remote(
|
|
remote: "origin",
|
|
remote_branch: branch,
|
|
force: true,
|
|
set_upstream: true
|
|
)
|
|
create_pull_request(
|
|
api_token: ENV['GITHUB_TOKEN'],
|
|
repo: "wikimedia/wikipedia-ios",
|
|
title: "Version bump",
|
|
head: branch,
|
|
base: "main",
|
|
body: "Please merge this in."
|
|
)
|
|
end
|
|
|
|
desc "Add a build tag for the current build number and push to repo. While this tags a build, tag_release sets a release tag."
|
|
lane :tag do |options|
|
|
prefix = options[:prefix] || "betas"
|
|
build_number = options[:build_number] || options[:build] || get_build_number
|
|
tag_name = "#{prefix}/#{build_number}"
|
|
message = options[:message] || ""
|
|
add_git_tag(tag: tag_name, message: message)
|
|
sh "git push origin --tags"
|
|
end
|
|
|
|
desc "Add a release tag for the latest beta and push to repo. For tagging non-releases, use `tag`."
|
|
lane :tag_release do |options|
|
|
specified_build = options[:build_tag]
|
|
if specified_build.nil? || specified_build.empty?
|
|
latest_beta = get_latest_build_number()
|
|
sh "git checkout betas/#{latest_beta}"
|
|
else
|
|
sh "git checkout #{specified_build}"
|
|
end
|
|
version = options[:version] || get_version_number_from_options(options)
|
|
tag_name = "releases/#{version}"
|
|
add_git_tag(tag: tag_name)
|
|
sh "git push origin --tags && git checkout main"
|
|
set_github_release(
|
|
repository_name: "wikimedia/wikipedia-ios",
|
|
api_token: ENV['GITHUB_TOKEN'],
|
|
name: version,
|
|
tag_name: tag_name,
|
|
description: "release to iOS app store"
|
|
)
|
|
end
|
|
|
|
desc "Build the app for distribution"
|
|
lane :build do |options|
|
|
project_dir = ".."
|
|
build_dir = "../build"
|
|
|
|
product_name = options[:product_name] || "Wikipedia"
|
|
project_name = options[:project] || product_name
|
|
scheme_name = options[:scheme] || product_name
|
|
version = options[:version] || ''
|
|
number = options[:number] || ''
|
|
|
|
read_xcversion
|
|
|
|
sh "xcodebuild -project \"#{project_dir}/#{project_name}.xcodeproj\" -scheme \"#{scheme_name}\" -archivePath \"#{build_dir}/#{product_name}.xcarchive\" archive"
|
|
sh "xcodebuild -exportArchive -exportOptionsPlist ExportOptions.plist -archivePath \"#{build_dir}/#{product_name}.xcarchive\" -exportPath \"#{build_dir}\""
|
|
end
|
|
|
|
desc "Pushes both the production and staging app to TestFlight and tags the release. Only releases to internal testers. (This is very similar to `push_production`, although this command also tags the build in git.)"
|
|
lane :deploy do |options|
|
|
tag_prefix = "betas"
|
|
last_build = get_latest_build_number(prefix: tag_prefix)
|
|
build = options[:build] || last_build + 1
|
|
last_public_release_tag = get_latest_tag_with_prefix(prefix: "releases/")[0..-2]
|
|
last_public_release_number = last_public_release_tag.gsub("releases/", "")
|
|
|
|
full_merges_since_last_build = get_recent_commits(start: "#{tag_prefix}/#{last_build}", is_brief: false)
|
|
full_merges_since_last_release = get_recent_commits(start: last_public_release_tag, is_brief: false)
|
|
full_changelog = "\n__New since last build (#{last_build})__\n#{full_merges_since_last_build.empty? ? 'None' : full_merges_since_last_build}\n\n" +
|
|
"__New since last public release (#{last_public_release_number})__\n#{full_merges_since_last_release.empty? ? 'None' : full_merges_since_last_release}"
|
|
|
|
brief_merges_since_last_build = get_recent_commits(start: "betas/#{last_build}", is_brief: true)
|
|
brief_merges_since_last_release = get_recent_commits(start: last_public_release_tag, is_brief: true)
|
|
brief_changelog = "__New since last build (#{last_build})__\n#{brief_merges_since_last_build.empty? ? 'None' : brief_merges_since_last_build}\n\n" +
|
|
"__New since last public release (#{last_public_release_number})__\n#{brief_merges_since_last_release.empty? ? 'None' : brief_merges_since_last_release}"
|
|
|
|
push_production(build: build, changelog: brief_changelog)
|
|
tag(prefix: tag_prefix, build_number: build, message: full_changelog)
|
|
push_staging(build: build)
|
|
end
|
|
|
|
desc "Updates version, builds, and pushes the production build to TestFlight. Only releases to internal testers."
|
|
lane :push_production do |options|
|
|
push(
|
|
product_name: "Wikipedia",
|
|
app_identifier: "org.wikimedia.wikipedia",
|
|
build: options[:build],
|
|
changelog: options[:changelog]
|
|
)
|
|
end
|
|
|
|
desc "Updates version, builds, and pushes the staging build to TestFlight. Only releases to internal testers."
|
|
lane :push_staging do |options|
|
|
push(
|
|
product_name: "Staging",
|
|
app_identifier: "org.wikimedia.wikipedia.tfbeta",
|
|
build: options[:build]
|
|
)
|
|
end
|
|
|
|
desc "Updates version, builds, and pushes experimental build to TestFlight. Only releases to internal testers."
|
|
lane :push_experimental do |options|
|
|
tag_prefix = "alphas"
|
|
build = options[:build] || get_latest_build_number(prefix: tag_prefix) + 1
|
|
push(
|
|
product_name: "Experimental",
|
|
app_identifier: "org.wikimedia.wikipedia.tfalpha",
|
|
build: build
|
|
)
|
|
tag(prefix: tag_prefix, build_number: build)
|
|
end
|
|
|
|
lane :get_latest_tag_with_prefix do |options|
|
|
prefix = options[:prefix] || "betas/"
|
|
`git tag -l #{prefix}* --sort=-creatordate | head -n 1`
|
|
end
|
|
|
|
lane :get_latest_build_number do |options|
|
|
prefix = options[:prefix] || "betas"
|
|
prefix = "#{prefix}/"
|
|
get_latest_tag_with_prefix(prefix: prefix)[prefix.length..-1].to_i
|
|
end
|
|
|
|
lane :get_recent_commits do |options|
|
|
start = options[:start] || "HEAD"
|
|
is_brief = options[:is_brief] || false
|
|
format = is_brief ? '• %b (%s)' : '• %h - %b (%s)'
|
|
small_sed = "s/(Merge pull.*\\(#[0-9]*\\).*)/(\\1)/"
|
|
sed_removal = is_brief ? small_sed : "s/Merge pull request //g"
|
|
|
|
if is_brief
|
|
list_without_localizations = `git log #{start}..HEAD --merges --first-parent origin/main --grep="Merge branch 'main' into" --grep="Localisation updates from" --invert-grep --pretty=format:"#{format}" | sed '#{sed_removal}'`
|
|
localization_numbers = `git log #{start}..HEAD --merges --first-parent origin/main --grep="Localisation updates from" --pretty=format:"%s" | sed "s/Merge pull.*\\(#[0-9]*\\).*/\\1/" | xargs`
|
|
localizations_list = "• Localisation updates from https://translatewiki.net. Pull requests: " + localization_numbers
|
|
localization_numbers.empty? ? list_without_localizations : "#{list_without_localizations}\n#{localizations_list}"
|
|
else
|
|
`git log #{start}..HEAD --merges --first-parent origin/main --grep="Merge branch 'main' into" --invert-grep --pretty=format:"#{format}" | sed '#{sed_removal}'`
|
|
end
|
|
end
|
|
|
|
desc "updates version, builds, and pushes to TestFlight"
|
|
lane :push do |options|
|
|
build_dir = "build"
|
|
product_name = options[:product_name] || "Wikipedia"
|
|
app_identifier = options[:app_identifier] || "org.wikimedia.wikipedia"
|
|
ipa_path = "#{build_dir}/#{product_name}.ipa"
|
|
build_number = options[:build] || get_latest_build_number(prefix: "betas") + 1
|
|
version = get_version_number_from_options(options)
|
|
apple_key = `cat ~/AuthKey.p8`
|
|
issuer_id = `cat ~/issuerID.txt`
|
|
key_id = `cat ~/keyID.txt`
|
|
api_key = app_store_connect_api_key(
|
|
key_id: key_id,
|
|
issuer_id: issuer_id,
|
|
key_content: apple_key
|
|
)
|
|
|
|
increment_build_number(
|
|
build_number: build_number
|
|
)
|
|
|
|
# the changelog was overwriting whatever custom test notes we added
|
|
# changelog_from_git_commits(
|
|
# pretty: '- (%ae) %s', # Optional, lets you provide a custom format to apply to each commit when generating the changelog text
|
|
# tag_match_pattern: "#{tag_prefix}/*", # Optional, lets you search for a tag name that matches a glob(7) pattern
|
|
# include_merges: false # Optional, lets you filter out merge commits
|
|
# )
|
|
|
|
build(
|
|
product_name: product_name,
|
|
project: "Wikipedia",
|
|
number: build_number,
|
|
version: version
|
|
)
|
|
|
|
pilot(
|
|
api_key: api_key,
|
|
ipa: ipa_path,
|
|
skip_waiting_for_build_processing: true,
|
|
skip_submission: true,
|
|
distribute_external: false,
|
|
app_identifier: app_identifier,
|
|
beta_app_feedback_email: "mobile-ios-wikipedia@wikimedia.org",
|
|
changelog: options[:changelog]
|
|
)
|
|
end
|
|
|
|
desc "Upload app store metadata"
|
|
lane :upload_app_store_metadata do
|
|
deliver(skip_binary_upload: true, skip_screenshots: true)
|
|
end
|
|
|
|
desc "Download dSYMs from iTunes Connect"
|
|
lane :dsyms do |options|
|
|
app_identifier = options[:app_identifier]
|
|
version = options[:version]
|
|
build_number = options[:build_number] || latest_testflight_build_number(app_identifier: app_identifier)
|
|
ipa_path = options[:ipa_path]
|
|
output_directory = options[:output_directory] || "build"
|
|
|
|
raise "Missing parameters" unless app_identifier && version && build_number && ipa_path && output_directory
|
|
|
|
download_dsyms(
|
|
build_number: build_number.to_s,
|
|
version: version.to_s,
|
|
app_identifier: app_identifier,
|
|
output_directory: output_directory
|
|
) # Download dSYM files from iTC
|
|
end
|
|
|
|
lane :dsyms_alpha do |options|
|
|
app_identifier = "org.wikimedia.wikipedia.tfalpha"
|
|
ipa_path = "build/Wikipedia Alpha.ipa"
|
|
version = options[:version] || get_version_number_from_options(options)
|
|
dsyms(
|
|
app_identifier: app_identifier,
|
|
version: version,
|
|
build_number: options[:build_number],
|
|
ipa_path: ipa_path
|
|
)
|
|
end
|
|
|
|
lane :dsyms_beta do |options|
|
|
app_identifier = "org.wikimedia.wikipedia"
|
|
ipa_path = "build/Wikipedia.ipa"
|
|
version = options[:version] || get_version_number_from_options(options)
|
|
dsyms(
|
|
app_identifier: app_identifier,
|
|
version: version,
|
|
build_number: options[:build_number] || options[:build],
|
|
ipa_path: ipa_path
|
|
)
|
|
end
|
|
|
|
lane :dsyms_beta_app do |options|
|
|
app_identifier = "org.wikimedia.wikipedia.tfbeta"
|
|
ipa_path = "build/Wikipedia.ipa"
|
|
version = options[:version] || get_version_number_from_options(options)
|
|
dsyms(
|
|
app_identifier: app_identifier,
|
|
version: version,
|
|
build_number: options[:build_number] || options[:build],
|
|
ipa_path: ipa_path
|
|
)
|
|
end
|
|
|
|
end
|