* initial Detox setup for mobile UI automation * fix iOS allow permission on opening the app, add npm script to root folder, fix test when using longer site URL and add detox dependency to root for android build dependency * remove detox proguardFile * update packages and emulator * change folder build on local and CI * add test to post a message, ability to have test in isolation, server API commands, server config, dependency updates and update folder structure * update snapshot * update detox and do clean up * update dependencies
921 lines
31 KiB
Ruby
921 lines
31 KiB
Ruby
fastlane_version '2.71.0'
|
|
|
|
fastlane_require 'aws-sdk-s3'
|
|
fastlane_require 'erb'
|
|
fastlane_require 'json'
|
|
fastlane_require 'pathname'
|
|
|
|
skip_docs
|
|
|
|
configured = false
|
|
is_build_pr = false
|
|
|
|
# Executes before anything else use to setup the script
|
|
before_all do
|
|
is_build_pr = ENV['BUILD_PR'] == 'true'
|
|
if is_build_pr && ENV['CIRCLECI'] == 'true'
|
|
ENV['BRANCH_TO_BUILD'] = ENV['CIRCLE_BRANCH']
|
|
end
|
|
|
|
if ENV['CIRCLECI'] != 'true'
|
|
# Raises an error is git is not clean
|
|
if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
|
|
ensure_git_status_clean
|
|
end
|
|
|
|
# Block to ensure we are on the right branch
|
|
branch = ENV['BRANCH_TO_BUILD'] || ENV['GIT_BRANCH']
|
|
begin
|
|
ensure_git_branch(
|
|
branch: branch
|
|
)
|
|
rescue
|
|
sh "git checkout #{branch}"
|
|
UI.success("Using branch \"#{branch}\"")
|
|
end
|
|
|
|
# If we are going to commit changes to git create a separate branch
|
|
# so no changes are done in the branch that is being built
|
|
if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
|
|
local_branch = ENV['GIT_LOCAL_BRANCH'] || 'build'
|
|
sh "git checkout -b #{local_branch}"
|
|
UI.success("Creating branch \"#{local_branch}\"")
|
|
end
|
|
end
|
|
end
|
|
|
|
after_all do |lane|
|
|
if ENV['CIRCLECI'] != 'true'
|
|
if lane.to_s == 'build'
|
|
submit_to_store
|
|
end
|
|
|
|
if ENV['RESET_GIT_BRANCH'] == 'true'
|
|
branch = ENV['BRANCH_TO_BUILD'] || 'master'
|
|
package_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta'
|
|
beta_dir = '../android/app/src/main/java/com/mattermost/rnbeta'
|
|
release_dir = "../android/app/src/main/java/#{package_id.gsub '.', '/'}"
|
|
|
|
if beta_dir != release_dir
|
|
sh "rm -rf #{release_dir}"
|
|
end
|
|
|
|
reset_git_repo(
|
|
force: true,
|
|
skip_clean: true
|
|
)
|
|
sh "git checkout #{branch}"
|
|
|
|
if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
|
|
local_branch = ENV['GIT_LOCAL_BRANCH'] || 'build'
|
|
sh "git branch -D #{local_branch}"
|
|
UI.success("Deleted working branch \"#{local_branch}\"")
|
|
if lane.to_s == 'build_pr'
|
|
sh 'git checkout master'
|
|
## Remove the branch for the PR
|
|
sh "git branch -D #{branch}"
|
|
UI.success("Deleted PR branch \"#{branch}\"")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
desc 'Increment version number for both Android and iOS'
|
|
lane :set_app_version do
|
|
version_number = ENV['VERSION_NUMBER']
|
|
unless version_number.nil? || version_number.empty?
|
|
package = load_config_json('../package.json')
|
|
package['version'] = version_number
|
|
save_config_json('../package.json', package)
|
|
|
|
lock = load_config_json('../package-lock.json')
|
|
lock['version'] = version_number
|
|
save_config_json('../package-lock.json', lock)
|
|
|
|
android_set_version_name(
|
|
gradle_file: './android/app/build.gradle',
|
|
version_name: version_number
|
|
)
|
|
|
|
increment_version_number(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
version_number: version_number
|
|
)
|
|
|
|
if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
|
|
msg = ENV['INCREMENT_VERSION_NUMBER_MESSAGE'] || 'Bump app version number to '
|
|
commit_message = "#{msg} #{version_number.to_s}"
|
|
build_folder_path = Dir[File.expand_path('..')].first
|
|
repo_path = (sh "git -C #{build_folder_path} rev-parse --show-toplevel").strip
|
|
git_dirty_files = (sh "git -C #{repo_path} diff --name-only HEAD").split(" ").join(' ')
|
|
|
|
unless git_dirty_files.empty?
|
|
sh "git -C #{repo_path} commit -m \"#{commit_message}\" #{git_dirty_files}"
|
|
UI.success("Successfully committed \"#{git_dirty_files}\" 💾.")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
desc 'Increments the build number for both Android and iOS'
|
|
lane :set_app_build_number do
|
|
## set the build number for both platforms
|
|
# use the one for iOS if no env variable set
|
|
if ENV['INCREMENT_BUILD_NUMBER'] === 'true'
|
|
build_number = ENV['BUILD_NUMBER'] || (get_build_number(xcodeproj: './ios/Mattermost.xcodeproj').to_i + 1)
|
|
increment_build_number(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
build_number: build_number
|
|
)
|
|
android_set_version_code(
|
|
gradle_file: './android/app/build.gradle',
|
|
version_code: build_number
|
|
)
|
|
|
|
|
|
if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
|
|
msg = ENV['INCREMENT_BUILD_NUMBER_MESSAGE'] || 'Bump app build number to '
|
|
commit_message = "#{msg} #{build_number.to_s}"
|
|
build_folder_path = Dir[File.expand_path('..')].first
|
|
repo_path = (sh "git -C #{build_folder_path} rev-parse --show-toplevel").strip
|
|
git_dirty_files = (sh "git -C #{repo_path} diff --name-only HEAD").split(" ").join(' ')
|
|
|
|
unless git_dirty_files.empty?
|
|
sh "git -C #{repo_path} commit -m \"#{commit_message}\" #{git_dirty_files}"
|
|
UI.success("Successfully committed \"#{git_dirty_files}\" 💾.")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
desc 'Configure the app before building'
|
|
lane :configure do
|
|
json = load_config_json('../dist/assets/config.json')
|
|
|
|
# Set the Segment API Key
|
|
unless ENV['RUDDER_API_KEY'].nil? || ENV['RUDDER_API_KEY'].empty?
|
|
json['RudderApiKey'] = ENV['RUDDER_API_KEY']
|
|
end
|
|
|
|
# Configure Sentry if enabled
|
|
if ENV['SENTRY_ENABLED'] == 'true'
|
|
json['SentryEnabled'] = true
|
|
json['SentryOrg'] = ENV['SENTRY_ORG']
|
|
json['SentryProjectIos'] = ENV['SENTRY_PROJECT_IOS']
|
|
json['SentryProjectAndroid'] = ENV['SENTRY_PROJECT_ANDROID']
|
|
json['SentryDsnIos'] = ENV['SENTRY_DSN_IOS']
|
|
json['SentryDsnAndroid'] = ENV['SENTRY_DSN_ANDROID']
|
|
end
|
|
|
|
# Save the config.json file
|
|
save_config_json('../dist/assets/config.json', json)
|
|
|
|
configured = true
|
|
end
|
|
|
|
desc 'Build the app for Android and iOS'
|
|
lane :build do |options|
|
|
configure
|
|
set_app_version
|
|
set_app_build_number
|
|
|
|
# Build the android app
|
|
self.runner.current_platform = :android
|
|
build
|
|
|
|
# Build the ios app
|
|
self.runner.current_platform = :ios
|
|
build
|
|
end
|
|
|
|
desc 'Upload file to s3'
|
|
lane :upload_file_to_s3 do |options|
|
|
os_type = options[:os_type]
|
|
file = options[:file]
|
|
file_plist = ""
|
|
|
|
if file.nil? || file.empty?
|
|
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
|
filename = app_name.gsub(" ", "_")
|
|
|
|
if os_type == 'Android'
|
|
file = "#{filename}.apk"
|
|
elsif os_type == 'iOS'
|
|
file = "#{filename}.ipa"
|
|
file_plist = "#{filename}.plist"
|
|
end
|
|
end
|
|
|
|
build_folder_path = Dir[File.expand_path('..')].first
|
|
file_path = "#{build_folder_path}/#{file}"
|
|
|
|
unless ENV['AWS_BUCKET_NAME'].nil? || ENV['AWS_BUCKET_NAME'].empty? || ENV['AWS_REGION'].nil? || ENV['AWS_REGION'].empty? || file_path.nil?
|
|
s3_region = ENV['AWS_REGION']
|
|
s3_bucket = ENV['AWS_BUCKET_NAME']
|
|
s3_folder = ''
|
|
|
|
version_number = ''
|
|
build_number = ''
|
|
|
|
if is_build_pr
|
|
s3_folder = "#{ENV['AWS_FOLDER_NAME']}/#{ENV['BRANCH_TO_BUILD']}"
|
|
else
|
|
if os_type == 'Android'
|
|
version_number = android_get_version_name(gradle_file: './android/app/build.gradle')
|
|
build_number = android_get_version_code(gradle_file: './android/app/build.gradle')
|
|
elsif os_type == 'iOS'
|
|
version_number = get_version_number(xcodeproj: './ios/Mattermost.xcodeproj', target: 'Mattermost')
|
|
build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
|
|
end
|
|
|
|
s3_folder = "#{ENV['AWS_FOLDER_NAME']}/#{version_number}/#{build_number}"
|
|
end
|
|
|
|
s3 = Aws::S3::Resource.new(region: s3_region)
|
|
file_obj = s3.bucket(s3_bucket).object("#{s3_folder}/#{file}")
|
|
file_obj.upload_file("#{file_path}")
|
|
|
|
if is_build_pr
|
|
if os_type == 'Android'
|
|
install_url = "https://#{s3_bucket}/#{s3_folder}/#{file}"
|
|
elsif os_type == 'iOS'
|
|
current_build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
|
|
plist_template = File.read('plist.erb')
|
|
plist_body = ERB.new(plist_template).result(binding)
|
|
|
|
plist_obj = s3.bucket(s3_bucket).object("#{s3_folder}/#{file_plist}")
|
|
plist_obj.put(body: plist_body)
|
|
|
|
install_url = "itms-services://?action=download-manifest&url=https://#{s3_bucket}/#{s3_folder}/#{file_plist}"
|
|
end
|
|
|
|
qa_build_message({
|
|
:os_type => os_type,
|
|
:install_url => install_url
|
|
})
|
|
end
|
|
|
|
public_link = "https://#{s3_bucket}/#{s3_folder}/#{file}"
|
|
if file == 'Mattermost-simulator-x86_64.app.zip'
|
|
pretext = '#### New iOS build for VM/Simulator'
|
|
msg = "Download link: #{public_link}"
|
|
send_message_to_mattermost({
|
|
:version_number => version_number,
|
|
:build_number => build_number,
|
|
:pretext => pretext,
|
|
:title => '',
|
|
:thumb_url => 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png',
|
|
:msg => msg,
|
|
:default_payloads => [],
|
|
:success => true,
|
|
})
|
|
end
|
|
|
|
UI.success("S3 bucket @#{s3_bucket}, object @#{s3_folder}/#{file}")
|
|
UI.success("S3 public path: #{public_link}")
|
|
end
|
|
end
|
|
|
|
desc 'Create GitHub release'
|
|
lane :github do
|
|
tag = ENV['CIRCLE_TAG'] || ENV['TAG']
|
|
|
|
if tag
|
|
version = android_get_version_name(gradle_file: './android/app/build.gradle')
|
|
build = android_get_version_code(gradle_file: './android/app/build.gradle')
|
|
changelog = File.read("metadata/changelog")
|
|
changelog.concat("* Android [Mattermost.apk](https://releases.mattermost.com/mattermost-mobile/#{version}/#{build}/Mattermost.apk)\n")
|
|
changelog.concat("* iOS [Mattermost.ipa](https://releases.mattermost.com/mattermost-mobile/#{version}/#{build}/Mattermost.ipa)")
|
|
|
|
github_release = set_github_release(
|
|
repository_name: "mattermost/mattermost-mobile",
|
|
api_token: ENV["GITHUB_TOKEN"],
|
|
name: "Mobile Version #{version}",
|
|
tag_name: tag,
|
|
description: changelog,
|
|
upload_assets: ["./Mattermost-unsigned.ipa", "./Mattermost-unsigned.apk"],
|
|
is_draft: true
|
|
)
|
|
end
|
|
end
|
|
|
|
platform :ios do
|
|
before_all do
|
|
if ENV['CIRCLECI'] == 'true'
|
|
setup_circle_ci
|
|
end
|
|
end
|
|
|
|
desc 'Get iOS adhoc profiles'
|
|
lane :adhoc do
|
|
if ENV['MATCH_TYPE'] != 'adhoc' && !ENV['MATCH_PASSWORD'].nil? && !ENV['MATCH_PASSWORD'].empty?
|
|
match(
|
|
type: 'adhoc'
|
|
)
|
|
end
|
|
end
|
|
|
|
desc 'Build iOS app'
|
|
lane :build do
|
|
unless configured
|
|
configure
|
|
end
|
|
update_identifiers
|
|
replace_assets
|
|
build_ios
|
|
upload_file_to_s3({:os_type => "iOS"})
|
|
end
|
|
|
|
desc 'Build an unsigned ipa'
|
|
lane :unsigned do
|
|
UI.success('Building unsigned iOS app')
|
|
|
|
ENV['APP_NAME'] = 'Mattermost'
|
|
ENV['REPLACE_ASSETS'] = 'true'
|
|
ENV['BUILD_FOR_RELEASE'] = 'true'
|
|
ENV['APP_SCHEME'] = 'mattermost-mobile'
|
|
|
|
update_identifiers
|
|
replace_assets
|
|
|
|
sh 'mkdir -p ../build-ios'
|
|
sh 'cd ../ios/ && xcodebuild -workspace Mattermost.xcworkspace/ -scheme Mattermost -sdk iphoneos -configuration Release -parallelizeTargets -resultBundlePath ../build-ios/result -derivedDataPath ../build-ios/ CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO'
|
|
sh 'cd ../build-ios/ && mkdir -p Payload && cp -R Build/Products/Release-iphoneos/Mattermost.app Payload/ && zip -r Mattermost-unsigned.ipa Payload/'
|
|
sh 'mv ../build-ios/Mattermost-unsigned.ipa ../'
|
|
sh 'rm -rf ../build-ios/'
|
|
end
|
|
|
|
lane :simulator do
|
|
UI.success('Building iOS app for simulator')
|
|
|
|
ENV['APP_NAME'] = 'Mattermost'
|
|
ENV['REPLACE_ASSETS'] = 'true'
|
|
ENV['BUILD_FOR_RELEASE'] = 'true'
|
|
ENV['APP_SCHEME'] = 'mattermost-mobile'
|
|
|
|
update_identifiers
|
|
replace_assets
|
|
|
|
sh 'cd ../ios && xcodebuild -workspace Mattermost.xcworkspace -scheme Mattermost -arch x86_64 -sdk iphonesimulator -configuration Release -parallelizeTargets -derivedDataPath ../build-ios ENABLE_BITCODE=NO CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO ENABLE_BITCODE=NO'
|
|
|
|
data_path = 'ios'
|
|
if ENV['CIRCLECI'] == 'true'
|
|
data_path = 'build-ios'
|
|
end
|
|
|
|
sh "cd ../#{data_path}/Build/Products/Release-iphonesimulator && zip -r Mattermost-simulator-x86_64.app.zip Mattermost.app"
|
|
sh "mv ../#{data_path}/Build/Products/Release-iphonesimulator/Mattermost-simulator-x86_64.app.zip ../"
|
|
|
|
upload_file_to_s3({
|
|
:os_type => "iOS",
|
|
:file => "Mattermost-simulator-x86_64.app.zip"
|
|
})
|
|
end
|
|
|
|
lane :update_identifiers do
|
|
# Set the name for the app
|
|
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
|
update_info_plist(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
plist_path: 'Mattermost/Info.plist',
|
|
display_name: app_name
|
|
)
|
|
|
|
# Set the notification service extension bundle identifier
|
|
notification_bundle_id = ENV['NOTIFICATION_SERVICE_IDENTIFIER'] || 'com.mattermost.rnbeta.NotificationService'
|
|
update_app_identifier(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
plist_path: 'NotificationService/Info.plist',
|
|
app_identifier: notification_bundle_id
|
|
)
|
|
|
|
find_replace_string(
|
|
path_to_file: './ios/Mattermost.xcodeproj/project.pbxproj',
|
|
old_string: 'com.mattermost.rnbeta.NotificationService',
|
|
new_string: notification_bundle_id
|
|
)
|
|
|
|
# Set the share extension bundle identifier
|
|
extension_bundle_id = ENV['EXTENSION_APP_IDENTIFIER'] || 'com.mattermost.rnbeta.MattermostShare'
|
|
update_app_identifier(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
plist_path: 'MattermostShare/Info.plist',
|
|
app_identifier: extension_bundle_id
|
|
)
|
|
|
|
find_replace_string(
|
|
path_to_file: './ios/Mattermost.xcodeproj/project.pbxproj',
|
|
old_string: 'com.mattermost.rnbeta.MattermostShare',
|
|
new_string: extension_bundle_id
|
|
)
|
|
|
|
# Set the app bundle id
|
|
app_bundle_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta'
|
|
update_app_identifier(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
plist_path: 'Mattermost/Info.plist',
|
|
app_identifier: app_bundle_id
|
|
)
|
|
|
|
find_replace_string(
|
|
path_to_file: './ios/Mattermost.xcodeproj/project.pbxproj',
|
|
old_string: 'com.mattermost.rnbeta',
|
|
new_string: app_bundle_id
|
|
)
|
|
|
|
# Set the deep link prefix
|
|
app_scheme = ENV['APP_SCHEME'] || 'mattermost'
|
|
update_info_plist(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
plist_path: 'Mattermost/Info.plist',
|
|
block: proc do |plist|
|
|
urlScheme = plist["CFBundleURLTypes"].find{|scheme| scheme["CFBundleURLName"] == "com.mattermost"}
|
|
urlScheme[:CFBundleURLSchemes] = [app_scheme]
|
|
end
|
|
)
|
|
|
|
# If set update the development team
|
|
unless ENV['FASTLANE_TEAM_ID'].nil? || ENV['FASTLANE_TEAM_ID'].empty?
|
|
update_project_team(
|
|
path: './ios/Mattermost.xcodeproj',
|
|
teamid: ENV['FASTLANE_TEAM_ID']
|
|
)
|
|
end
|
|
|
|
# Set the ICloud container
|
|
icloud_container = ENV['IOS_ICLOUD_CONTAINER'] || 'iCloud.com.mattermost.rnbeta'
|
|
update_icloud_container_identifiers(
|
|
entitlements_file: './ios/Mattermost/Mattermost.entitlements',
|
|
icloud_container_identifiers: [icloud_container]
|
|
)
|
|
|
|
# Set the app group id to share data between the app and the extension
|
|
app_group_id = ENV['IOS_APP_GROUP'] || 'group.com.mattermost.rnbeta'
|
|
update_app_group_identifiers(
|
|
entitlements_file: './ios/Mattermost/Mattermost.entitlements',
|
|
app_group_identifiers: [app_group_id]
|
|
)
|
|
|
|
find_replace_string(
|
|
path_to_file: './ios/UploadAttachments/UploadAttachments/MMMConstants.m',
|
|
old_string: 'group.com.mattermost.rnbeta',
|
|
new_string: app_group_id
|
|
)
|
|
|
|
find_replace_string(
|
|
path_to_file: './node_modules/react-native-mmkv-storage/ios/MMKVStorage.m',
|
|
old_string: 'group.com.mattermost.rnbeta',
|
|
new_string: app_group_id
|
|
)
|
|
|
|
update_app_group_identifiers(
|
|
entitlements_file: './ios/MattermostShare/MattermostShare.entitlements',
|
|
app_group_identifiers: [app_group_id]
|
|
)
|
|
|
|
update_app_group_identifiers(
|
|
entitlements_file: './ios/NotificationService/NotificationService.entitlements',
|
|
app_group_identifiers: [app_group_id]
|
|
)
|
|
|
|
# Sync the provisioning profiles using match
|
|
if ENV['SYNC_PROVISIONING_PROFILES'] == 'true' && !ENV['MATCH_PASSWORD'].nil? && !ENV['MATCH_PASSWORD'].empty?
|
|
match(type: ENV['MATCH_TYPE'] || 'adhoc')
|
|
end
|
|
end
|
|
|
|
lane :replace_assets do
|
|
if ENV['REPLACE_ASSETS'] == 'true'
|
|
sh 'cp -R ../dist/assets/release/icons/ios/* ../ios/Mattermost/Images.xcassets/AppIcon.appiconset/'
|
|
sh 'cp -R ../dist/assets/release/splash_screen/ios/* ../ios/SplashScreenResource/'
|
|
end
|
|
end
|
|
|
|
lane :deploy do |options|
|
|
ipa_path = options[:file]
|
|
|
|
unless ipa_path.nil?
|
|
submit_to_testflight(ipa_path)
|
|
end
|
|
end
|
|
|
|
error do |lane, exception|
|
|
version = get_version_number(xcodeproj: './ios/Mattermost.xcodeproj', target: 'Mattermost')
|
|
build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
|
|
send_message_to_mattermost({
|
|
:version_number => version,
|
|
:build_number => build_number,
|
|
:pretext => '',
|
|
:title => 'Unsuccessful Build',
|
|
:thumb_url => 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png',
|
|
:msg => exception.message,
|
|
:default_payloads => [:lane],
|
|
:success => false
|
|
})
|
|
end
|
|
|
|
def setup_code_signing
|
|
update_code_signing_settings(
|
|
use_automatic_signing: false,
|
|
path: './ios/Mattermost.xcodeproj'
|
|
)
|
|
|
|
ENV['MATCH_APP_IDENTIFIER'].split(',').each do |id|
|
|
target = 'Mattermost'
|
|
if id.include? 'NotificationService'
|
|
target = 'NotificationService'
|
|
elsif id.include? 'MattermostShare'
|
|
target = 'MattermostShare'
|
|
end
|
|
|
|
profile = "sigh_#{id}_#{ENV['MATCH_TYPE']}"
|
|
config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug'
|
|
|
|
update_project_provisioning(
|
|
xcodeproj: './ios/Mattermost.xcodeproj',
|
|
profile: ENV["#{profile}_profile-path"], # optional if you use sigh
|
|
target_filter: ".*#{target}$", # matches name or type of a target
|
|
build_configuration: config_mode,
|
|
code_signing_identity: 'iPhone Distribution' # optionally specify the codesigning identity
|
|
)
|
|
end
|
|
end
|
|
|
|
def build_ios
|
|
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
|
app_name_sub = app_name.gsub(" ", "_")
|
|
config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug'
|
|
method = ENV['IOS_BUILD_EXPORT_METHOD'].nil? || ENV['IOS_BUILD_EXPORT_METHOD'].empty? ? 'ad-hoc' : ENV['IOS_BUILD_EXPORT_METHOD']
|
|
|
|
setup_code_signing
|
|
|
|
gym(
|
|
clean: true,
|
|
scheme: 'Mattermost',
|
|
configuration: config_mode,
|
|
workspace: './ios/Mattermost.xcworkspace',
|
|
export_method: method,
|
|
skip_profile_detection: true,
|
|
output_name: "#{app_name_sub}.ipa",
|
|
export_xcargs: "-allowProvisioningUpdates",
|
|
export_options: {
|
|
signingStyle: 'manual',
|
|
iCloudContainerEnvironment: 'Production'
|
|
}
|
|
)
|
|
end
|
|
|
|
end
|
|
|
|
platform :android do
|
|
desc 'Build Android app'
|
|
lane :build do
|
|
unless configured
|
|
configure
|
|
end
|
|
configure_telemetry_android
|
|
update_identifiers
|
|
replace_assets
|
|
link_sentry_android
|
|
build_android
|
|
move_apk_to_root
|
|
upload_file_to_s3({:os_type => "Android"})
|
|
end
|
|
|
|
desc 'Build an unsigned apk'
|
|
lane :unsigned do
|
|
UI.success('Building unsigned Android app')
|
|
|
|
ENV['APP_NAME'] = 'Mattermost'
|
|
ENV['REPLACE_ASSETS'] = 'true'
|
|
ENV['BUILD_FOR_RELEASE'] = 'true'
|
|
ENV['APP_SCHEME'] = 'mattermost-mobile'
|
|
|
|
update_identifiers
|
|
replace_assets
|
|
|
|
gradle(
|
|
task: 'assemble',
|
|
build_type: 'Unsigned',
|
|
project_dir: 'android/'
|
|
)
|
|
|
|
sh "mv #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]} #{Pathname.new(File.expand_path(File.dirname(__FILE__))).parent.to_s}/Mattermost-unsigned.apk"
|
|
end
|
|
|
|
desc 'Update config and module/listener for Android telemetry'
|
|
lane :configure_telemetry_android do
|
|
if ENV['TELEMETRY_ENABLED'] == 'true' && ENV['TELEMETRY_URL'] != '' && ENV['TELEMETRY_API_KEY'] != ''
|
|
# Update telemetry config
|
|
json = load_config_json('../dist/assets/config.json')
|
|
json['TelemetryEnabled'] = true
|
|
json['TelemetryUrl'] = ENV['TELEMETRY_URL']
|
|
json['TelemetryApiKey'] = ENV['TELEMETRY_API_KEY']
|
|
save_config_json('../dist/assets/config.json', json)
|
|
|
|
beta_dir = './android/app/src/main/java/com/mattermost/rnbeta/'
|
|
|
|
# Listen to telemetry react markers
|
|
find_replace_string(
|
|
path_to_file: "#{beta_dir}MainApplication.java",
|
|
old_string: '// addReactMarkerListener();',
|
|
new_string: 'addReactMarkerListener();'
|
|
)
|
|
end
|
|
end
|
|
|
|
lane :update_identifiers do
|
|
# Set the name for the app
|
|
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
|
sh "echo '#{app_name}' > ../fastlane/metadata/android/en-US/title.txt"
|
|
android_change_string_app_name(
|
|
newName: app_name,
|
|
stringsFile: './android/app/src/main/res/values/strings.xml'
|
|
)
|
|
|
|
package_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta'
|
|
android_change_package_identifier(newIdentifier: package_id, manifest: './android/app/src/main/AndroidManifest.xml')
|
|
android_update_application_id(app_folder_name: 'android/app', application_id: package_id)
|
|
|
|
app_scheme = ENV['APP_SCHEME'] || 'mattermost'
|
|
find_replace_string(
|
|
path_to_file: "./android/app/src/main/AndroidManifest.xml",
|
|
old_string: 'scheme="mattermost"',
|
|
new_string: "scheme=\'#{app_scheme}\'"
|
|
)
|
|
|
|
beta_dir = './android/app/src/main/java/com/mattermost/rnbeta/'
|
|
release_dir = "./android/app/src/main/java/#{package_id.gsub '.', '/'}/"
|
|
if ENV['BUILD_FOR_RELEASE'] == 'true'
|
|
find_replace_string(
|
|
path_to_file: "#{beta_dir}MainApplication.java",
|
|
old_string: 'return BuildConfig.DEBUG;',
|
|
new_string: 'return false;'
|
|
)
|
|
end
|
|
|
|
if release_dir != beta_dir
|
|
unless Dir.exist?(".#{release_dir}")
|
|
FileUtils.mkdir_p ".#{release_dir}"
|
|
end
|
|
|
|
sh "mv .#{beta_dir}* .#{release_dir}"
|
|
|
|
find_replace_string(
|
|
path_to_file: './android/app/BUCK',
|
|
old_string: 'package com.mattermost.rnbeta;',
|
|
new_string: "package #{package_id};"
|
|
)
|
|
|
|
Dir.glob(".#{release_dir}*.java") do |item|
|
|
find_replace_string(
|
|
path_to_file: item[1..-1],
|
|
old_string: 'package com.mattermost.rnbeta;',
|
|
new_string: "package #{package_id};"
|
|
)
|
|
end
|
|
|
|
Dir.glob('../android/app/src/main/java/com/mattermost/share/*.java') do |item|
|
|
find_replace_string(
|
|
path_to_file: item[1..-1],
|
|
old_string: 'import com.mattermost.rnbeta.MainApplication;',
|
|
new_string: "import #{package_id}.MainApplication;"
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
lane :replace_assets do
|
|
if ENV['REPLACE_ASSETS'] == 'true'
|
|
sh 'cp -R ../dist/assets/release/icons/android/* ../android/app/src/main/res/'
|
|
sh 'cp -R ../dist/assets/release/splash_screen/android/* ../android/app/src/main/res/'
|
|
end
|
|
end
|
|
|
|
lane :deploy do |options|
|
|
apk_path = options[:file]
|
|
|
|
unless apk_path.nil?
|
|
submit_to_google_play(apk_path)
|
|
end
|
|
end
|
|
|
|
error do |lane, exception|
|
|
build_number = android_get_version_code(
|
|
gradle_file: './android/app/build.gradle'
|
|
)
|
|
version_number = android_get_version_name(
|
|
gradle_file: './android/app/build.gradle'
|
|
)
|
|
|
|
send_message_to_mattermost({
|
|
:version_number => version_number,
|
|
:build_number => build_number,
|
|
:pretext => '',
|
|
:title => 'Unsuccessful Build',
|
|
:thumb_url => 'https://lh3.ggpht.com/XL0CrI8skkxnboGct-duyg-bZ_MxJDTrjczyjdU8OP2PM1dmj7SP4jL1K8JQeMIB3AM=w300',
|
|
:msg => exception.message,
|
|
:default_payloads => [:lane],
|
|
:success => false,
|
|
})
|
|
end
|
|
|
|
def build_android
|
|
config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug'
|
|
|
|
gradle(
|
|
task: 'app:assemble',
|
|
build_type: config_mode,
|
|
project_dir: 'android/'
|
|
)
|
|
end
|
|
|
|
def move_apk_to_root
|
|
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
|
app_name_sub = app_name.gsub(" ", "_")
|
|
new_apk_path = "#{Pathname.new(File.expand_path(File.dirname(__FILE__))).parent.to_s}/#{app_name_sub}.apk"
|
|
apk_path = lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]
|
|
|
|
unless apk_path.nil?
|
|
sh "mv #{apk_path} #{new_apk_path}"
|
|
lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH] = new_apk_path
|
|
end
|
|
end
|
|
|
|
def link_sentry_android
|
|
if ENV['SENTRY_ENABLED'] == 'true'
|
|
url = 'https://sentry.io'
|
|
File.open('../android/sentry.properties', 'w+') do |f|
|
|
UI.message('Creating sentry.properties from environment')
|
|
f.write(
|
|
"defaults.url=#{url}\n"\
|
|
"defaults.org=#{ENV['SENTRY_ORG']}\n"\
|
|
"defaults.project=#{ENV['SENTRY_PROJECT_ANDROID']}\n"\
|
|
"auth.token=#{ENV['SENTRY_AUTH_TOKEN']}\n"
|
|
)
|
|
end
|
|
else
|
|
UI.message('Not creating sentry.properties because Sentry is disabled')
|
|
end
|
|
end
|
|
end
|
|
|
|
def load_config_json(json_path)
|
|
config_file = File.read(json_path)
|
|
JSON.parse(config_file)
|
|
end
|
|
|
|
def save_config_json(json_path, json)
|
|
File.open(json_path, 'w') do |f|
|
|
f.write(JSON.pretty_generate(json))
|
|
f.write("\n")
|
|
end
|
|
end
|
|
|
|
def send_message_to_mattermost(options)
|
|
unless ENV['MATTERMOST_WEBHOOK_URL'].nil? || ENV['MATTERMOST_WEBHOOK_URL'].empty?
|
|
mattermost(
|
|
pretext: options[:pretext],
|
|
message: options[:msg],
|
|
default_payloads: options[:default_payloads],
|
|
username: 'Fastlane',
|
|
icon_url: 'https://mattermost-plugin-media.s3.amazonaws.com/fastlane.png',
|
|
payload: {},
|
|
attachment_properties: {
|
|
title: options[:title],
|
|
thumb_url: options[:thumb_url],
|
|
fields: [{
|
|
title: 'Version',
|
|
value: options[:version_number],
|
|
short: true
|
|
},
|
|
{
|
|
title: 'Build Number',
|
|
value: options[:build_number],
|
|
short: true
|
|
}]
|
|
},
|
|
success: options[:success]
|
|
)
|
|
end
|
|
end
|
|
|
|
def submit_to_testflight(ipa_path)
|
|
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
|
app_name_sub = app_name.gsub(" ", "_")
|
|
|
|
if(File.file?(ipa_path))
|
|
UI.success("ipa file #{ipa_path}")
|
|
pilot(
|
|
ipa: ipa_path
|
|
)
|
|
else
|
|
UI.user_error! "ipa file does not exist #{ipa_path}"
|
|
return
|
|
end
|
|
|
|
version_number = get_version_number(xcodeproj: './ios/Mattermost.xcodeproj', target: 'Mattermost')
|
|
build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
|
|
s3_folder = "#{ENV['AWS_FOLDER_NAME']}/#{version_number}/#{build_number}"
|
|
public_link = "https://#{ENV['AWS_BUCKET_NAME']}/#{s3_folder}/#{app_name_sub}.ipa"
|
|
|
|
|
|
# Send a build message to Mattermost
|
|
pretext = '#### New iOS released ready to be published'
|
|
msg = "Release has been cut and is on TestFlight ready to be published.\nDownload link: #{public_link}"
|
|
|
|
if ENV['BETA_BUILD'] == 'true'
|
|
pretext = '#### New iOS beta published to TestFlight'
|
|
msg = "Sign up as a beta tester [here](https://testflight.apple.com/join/Q7Rx7K9P).\nDownload link: #{public_link}"
|
|
end
|
|
|
|
send_message_to_mattermost({
|
|
:version_number => version_number,
|
|
:build_number => build_number,
|
|
:pretext => pretext,
|
|
:title => '',
|
|
:thumb_url => 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png',
|
|
:msg => msg,
|
|
:default_payloads => [],
|
|
:success => true,
|
|
})
|
|
end
|
|
|
|
def submit_to_google_play(apk_path)
|
|
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
|
app_name_sub = app_name.gsub(" ", "_")
|
|
|
|
if(File.file?(apk_path))
|
|
UI.success("apk file #{apk_path}")
|
|
unless ENV['SUPPLY_JSON_KEY'].nil? || ENV['SUPPLY_JSON_KEY'].empty?
|
|
supply(
|
|
track: ENV['SUPPLY_TRACK'] || 'alpha',
|
|
apk: apk_path
|
|
)
|
|
end
|
|
else
|
|
UI.user_error! "apk file does not exist #{apk_path}"
|
|
return
|
|
end
|
|
|
|
version_number = android_get_version_name(gradle_file: './android/app/build.gradle')
|
|
build_number = android_get_version_code(gradle_file: './android/app/build.gradle')
|
|
s3_folder = "#{ENV['AWS_FOLDER_NAME']}/#{version_number}/#{build_number}"
|
|
public_link = "https://#{ENV['AWS_BUCKET_NAME']}/#{s3_folder}/#{app_name_sub}.apk"
|
|
|
|
# Send a build message to Mattermost
|
|
pretext = '#### New Android released ready to be published'
|
|
msg = "Release has been cut and is on the Beta track ready to be published.\nDownload link: #{public_link}"
|
|
|
|
if ENV['BETA_BUILD'] == 'true'
|
|
pretext = '#### New Android beta published to Google Play'
|
|
msg = "Sign up as a beta tester [here](https://play.google.com/apps/testing/com.mattermost.rnbeta).\nDownload link: #{public_link}"
|
|
end
|
|
|
|
send_message_to_mattermost({
|
|
:version_number => version_number,
|
|
:build_number => build_number,
|
|
:pretext => pretext,
|
|
:title => '',
|
|
:thumb_url => 'https://lh3.ggpht.com/XL0CrI8skkxnboGct-duyg-bZ_MxJDTrjczyjdU8OP2PM1dmj7SP4jL1K8JQeMIB3AM=w300',
|
|
:msg => msg,
|
|
:default_payloads => [],
|
|
:success => true,
|
|
})
|
|
end
|
|
|
|
def submit_to_store
|
|
apk_path = lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]
|
|
ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH]
|
|
|
|
# Submit to Google Play if required
|
|
if !apk_path.nil? && ENV['SUBMIT_ANDROID_TO_GOOGLE_PLAY'] == 'true'
|
|
submit_to_google_play(apk_path)
|
|
end
|
|
|
|
# Submit to TestFlight if required
|
|
if !ipa_path.nil? && ENV['SUBMIT_IOS_TO_TESTFLIGHT'] == 'true'
|
|
submit_to_testflight(ipa_path)
|
|
end
|
|
end
|
|
|
|
def qa_build_message(options)
|
|
abbreviated_commit_hash = last_git_commit[:abbreviated_commit_hash]
|
|
os_type = options[:os_type]
|
|
install_url = options[:install_url]
|
|
|
|
unless ENV['MATTERMOST_WEBHOOK_URL'].nil? || ENV['MATTERMOST_WEBHOOK_URL'].empty?
|
|
os_type = options[:os_type]
|
|
|
|
if os_type == 'Android'
|
|
msg = "QA build [#{abbreviated_commit_hash}](https://github.com/mattermost/mattermost-mobile/commit/#{abbreviated_commit_hash}) — [Android APK Link](#{install_url})"
|
|
mattermost(message: msg, username: 'Fastlane', icon_url: 'https://lh3.ggpht.com/XL0CrI8skkxnboGct-duyg-bZ_MxJDTrjczyjdU8OP2PM1dmj7SP4jL1K8JQeMIB3AM=w300')
|
|
elsif os_type == 'iOS'
|
|
msg = "QA build [#{abbreviated_commit_hash}](https://github.com/mattermost/mattermost-mobile/commit/#{abbreviated_commit_hash}) — [iOS pList Link](#{install_url})"
|
|
mattermost(message: msg, username: 'Fastlane', icon_url: 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png')
|
|
end
|
|
else
|
|
UI.success("PR Built for #{os_type}: #{install_url}")
|
|
end
|
|
end
|