fastlane_version '2.56.0' skip_docs platform :ios do before_all do |lane| if lane == :beta or lane === :release current_branch = (sh 'git rev-parse --abbrev-ref HEAD').chop! UI.user_error!("To cut a beta or a release you need to be on master or in a release branch. Current branch is #{current_branch} Exiting") unless current_branch == 'master' or current_branch.start_with?('release') if lane == :beta sh "git checkout -b ios-#{lane}" end end end after_all do |lane| if lane == :beta reset_git_repo( force: true, skip_clean: true ) sh 'git checkout master' sh "git branch -D ios-#{lane}" end end desc 'Build Release file' desc 'This will also make sure the profile is up to date' lane :dev do match(type: 'adhoc', app_identifier: 'com.mattermost.rnbeta') build_ios({ release: false, increment_build: false, ensure_git_status_clean: false, method: 'ad-hoc' }) end desc 'Submit a new Beta Build to Apple TestFlight' desc 'This will also make sure the profile is up to date' lane :beta do match(type: 'appstore', app_identifier: 'com.mattermost.rnbeta') configure_from_env() build_ios({ release: true, increment_build: true, ensure_git_status_clean: true, method: 'app-store' }) pilot(skip_waiting_for_build_processing: true) commit = last_git_commit push_to_git_remote( remote: 'origin', local_branch: 'ios-beta', force: false, tags: false ) unless ENV['GITHUB_TOKEN'].nil? create_pull_request( api_token: ENV['GITHUB_TOKEN'], repo: 'mattermost/mattermost-mobile', head: 'mattermost:ios-beta', base: 'master', title: "IOS #{commit[:message]}" ) end if ENV['MATTERMOST_WEBHOOK_URL'] testflight_url = ENV['TESTFLIGHT_URL'] send_message_for_ios( '#### New iOS beta published on TestFlight', '', "#ios-beta in #{testflight_url.nil? ? 'TestFlight' : "[TestFlight](#{testflight_url})"} on [#{Time.new.utc.to_s}]", [], true ) end end desc 'Deploy a new version to the App Store' lane :release do match(type: 'appstore', app_identifier: 'com.mattermost.rn') configure_from_env() # snapshot update_app_identifier( xcodeproj: './ios/Mattermost.xcodeproj', plist_path: 'Mattermost/Info.plist', app_identifier: 'com.mattermost.rn' ) update_info_plist( xcodeproj: './ios/Mattermost.xcodeproj', plist_path: 'Mattermost/Info.plist', display_name: 'Mattermost' ) sh 'cp -R ../assets/release/icons/ios/* ../ios/Mattermost/Images.xcassets/AppIcon.appiconset/' build_ios({ release: true, increment_build: false, ensure_git_status_clean: false, method: 'app-store' }) # deliver( # force: true, # skip_screenshots: true, # skip_metadata: true, # submit_for_review: false, #lets try this after the first release # automatic_release: false #lets try this after the first release # ) ### We are going to publish the app to the testflight first and not deliver it directly to the app store pilot(skip_waiting_for_build_processing: true) # frameit reset_git_repo( force: true, skip_clean: true ) if ENV['MATTERMOST_WEBHOOK_URL'] appstore_url = ENV['APPSTORE_URL'] send_message_for_ios( '#### New iOS release published on the App Store', '', "#ios-release in #{appstore_url.nil? ? 'App Store' : "[App Store](#{appstore_url})"} on [#{Time.new.utc.to_s}]", [], true ) end end desc 'Build an unsigned ipa' lane :unsigned do if ENV['SEGMENT_API_KEY'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SegmentApiKey": "3MT7rAoC0OP7yy3ThzqFSAtKzmzqtUPX"', new_string: "\"SegmentApiKey\": \"#{ENV['SEGMENT_API_KEY']}\"" ) end update_app_identifier( xcodeproj: './ios/Mattermost.xcodeproj', plist_path: 'Mattermost/Info.plist', app_identifier: 'com.mattermost.rn' ) update_info_plist( xcodeproj: './ios/Mattermost.xcodeproj', plist_path: 'Mattermost/Info.plist', display_name: 'Mattermost' ) sh 'cp -R ../assets/release/icons/ios/* ../ios/Mattermost/Images.xcassets/AppIcon.appiconset/' end error do |lane, exception| if ENV['MATTERMOST_WEBHOOK_URL'] send_message_for_ios('', 'Unsuccessful Build', exception.message, [:lane], false) end end def build_ios(options) if options[:ensure_git_status_clean] ensure_git_status_clean end if options[:increment_build] current_build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj').to_i increment_build_number( xcodeproj: './ios/Mattermost.xcodeproj', build_number: current_build_number + 1 ) commit_version_bump(xcodeproj: './ios/Mattermost.xcodeproj') end update_project_team( path: './ios/Mattermost.xcodeproj', teamid: ENV['FASTLANE_TEAM_ID'] ) gym( clean: true, scheme: 'Mattermost', configuration: (options[:release] ? 'Release' : 'Debug'), workspace: './ios/Mattermost.xcworkspace', export_method: options[:method] ) end def send_message_for_ios(pretext, title, msg, default_payloads, success) version = get_version_number(xcodeproj: './ios/Mattermost.xcodeproj') build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj') mattermost( pretext: pretext, message: msg, default_payloads: default_payloads, username: 'Fastlane', icon_url: 'https://s3-eu-west-1.amazonaws.com/fastlane.tools/fastlane.png', payload: {}, attachment_properties: { title: title, thumb_url: 'https://lh3.googleusercontent.com/Nkbo3QohCOU8bGqSYtwB88o03XxUwRAxRHNdXPB9zFvYFzTwD7naYa-GYJaelBp-OIc=w300', fields: [{ title: 'Version', value: version, short: true }, { title: 'Build Number', value: build_number, short: true }, { title: 'Built by', value: 'Jenkins', short: true }] }, success: success ) end end platform :android do before_all do |lane| if lane == :alpha or lane === :release current_branch = (sh 'git rev-parse --abbrev-ref HEAD').chop! UI.user_error!("To cut a beta or a release you need to be on master or in a release branch. Current branch is #{current_branch} Exiting") unless current_branch == 'master' or current_branch.start_with?('release') if lane == :alpha sh "git checkout -b android-#{lane}" end end end after_all do |lane| if lane == :alpha reset_git_repo( force: true, skip_clean: true ) sh 'git checkout master' sh "git branch -D android-#{lane}" end end desc 'Build Release file' lane :dev do build_android({release: true}) end desc 'Submit a new Beta Build to Google Play' lane :alpha do configure_from_env() build_android({ release: true, increment_build: true, ensure_git_status_clean: true }) supply( track: 'alpha', apk: "#{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]}", ) commit = last_git_commit push_to_git_remote( remote: 'origin', local_branch: 'android-alpha', force: false, tags: false ) unless ENV['GITHUB_TOKEN'].nil? create_pull_request( api_token: ENV['GITHUB_TOKEN'], repo: 'mattermost/mattermost-mobile', head: 'mattermost:android-alpha', base: 'master', title: "Android #{commit[:message]}" ) end if ENV['MATTERMOST_WEBHOOK_URL'] beta_url = ENV['GOOGLE_PLAY_BETA_URL'] send_message_for_android( '#### New Android beta published for Beta Testing', '', "#android-beta in #{beta_url.nil? ? 'Google Play Beta Program' : "[Google Play Beta Program](#{beta_url})"} on [#{Time.new.utc.to_s}]", [], true ) end end desc 'Deploy a new version to Google Play' lane :release do prepare_release() build_android({ release: true, increment_build: false, ensure_git_status_clean: false }) supply( track: 'beta', apk: "#{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]}", ) sh 'mv ../android/app/src/main/java/com/mattermost/rn/ ../android/app/src/main/java/com/mattermost/rnbeta/' reset_git_repo( force: true, skip_clean: true ) if ENV['MATTERMOST_WEBHOOK_URL'] google_play_url = ENV['GOOGLE_PLAY_URL'] send_message_for_android( '#### New Android beta published for Production', '', "#android-beta in #{google_play_url.nil? ? 'Google Play' : "[Google Play](#{google_play_url})"} on [#{Time.new.utc.to_s}]", [], true ) end end desc 'Build an unsigned apk' lane :unsigned do prepare_release() gradle( task: 'assemble', build_type: 'Unsigned', project_dir: 'android/' ) end error do |lane, exception| if ENV['MATTERMOST_WEBHOOK_URL'] send_message_for_android('', 'Unsuccessful Build', exception.message, [:lane], false) end end def prepare_release android_change_package_identifier(newIdentifier: 'com.mattermost.rn', manifest: './android/app/src/main/AndroidManifest.xml') android_change_string_app_name(newName: 'Mattermost', stringsFile: './android/app/src/main/res/values/strings.xml') android_update_application_id(app_folder_name: 'android/app', application_id: 'com.mattermost.rn') sh 'mv ../android/app/src/main/java/com/mattermost/rnbeta/ ../android/app/src/main/java/com/mattermost/rn/' sh 'cp -R ../assets/release/icons/android/* ../android/app/src/main/res/' find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/MainApplication.java', old_string: 'return BuildConfig.DEBUG;', new_string: 'return false;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/MainApplication.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/CustomPushNotification.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/MainActivity.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationsLifecycleFacade.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationDismissService.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationReplyService.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationPreferencesModule.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationPreferences.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/MattermostManagedModule.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/src/main/java/com/mattermost/rn/MattermostPackage.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './android/app/BUCK', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) find_replace_string( path_to_file: './fastlane/metadata/android/en-US/title.txt', old_string: 'Mattermost Beta', new_string: 'Mattermost' ) configure_from_env() end def build_android(options) if options[:ensure_git_status_clean] ensure_git_status_clean end if options[:increment_build] android_increment_version_code(app_folder_name: 'android/app') android_commit_version_bump( app_folder_name: 'android/app', force: true ) end link_sentry_android() gradle( task: 'assemble', build_type: (options[:release] ? 'Release' : 'Debug'), project_dir: 'android/' ) end def get_version_code(app_folder_name) version_code = '0' Dir.glob("../#{app_folder_name}/build.gradle") do |path| begin UI.message(" -> Found a build.gradle file at path: (#{path})!") file = File.new(path, 'r') while (line = file.gets) if line.include? 'versionCode' versionComponents = line.strip.split(' ') version_code = versionComponents[1].tr("\"",'') break end end file.close rescue => err UI.error("An exception occured while reading gradle file: #{err}") err end end if version_code == '0' UI.user_error!("Impossible to find the version code in the current project folder #{app_folder_name} 😭") else # Store the version name in the shared hash Actions.lane_context['VERSION_CODE']=version_code UI.success("👍 Version name found: #{version_code}") end return version_code end def get_version_name(app_folder_name) version_name = '0' Dir.glob("../#{app_folder_name}/build.gradle") do |path| begin file = File.new(path, 'r') while (line = file.gets) if line.include? 'versionName' versionComponents = line.strip.split(' ') version_name = versionComponents[1].tr("\"",'') break end end file.close rescue => err UI.error("An exception occured while readinf gradle file: #{err}") err end end if version_name == '0' UI.user_error!("Impossible to find the version name in the current project folder #{app_folder_name} 😭") else # Store the version name in the shared hash Actions.lane_context['VERSION_NAME']=version_name UI.success("👍 Version name found: #{version_name}") end return version_name end def send_message_for_android(pretext, title, msg, default_payloads, success) build_number = get_version_code('android/app') version_name = get_version_name('android/app') mattermost( pretext: pretext, message: msg, default_payloads: default_payloads, username: 'Fastlane', icon_url: 'https://s3-eu-west-1.amazonaws.com/fastlane.tools/fastlane.png', payload: {}, attachment_properties: { title: title, thumb_url: 'http://www.concretesolutions.com.br/blog/wp-content/uploads/2015/04/Android1.png', fields: [{ title: 'Version', value: version_name, short: true }, { title: 'Build Number', value: build_number, short: true }, { title: 'Built by', value: 'Jenkins', short: true }] }, success: success ) end end def configure_from_env() if ENV['SEGMENT_API_KEY'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SegmentApiKey": "3MT7rAoC0OP7yy3ThzqFSAtKzmzqtUPX"', new_string: "\"SegmentApiKey\": \"#{ENV['SEGMENT_API_KEY']}\"" ) end if ENV['SENTRY_ENABLED'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SentryEnabled": false', new_string: "\"SentryEnabled\": #{ENV['SENTRY_ENABLED']}" ) end if ENV['SENTRY_ORG'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SentryOrg": ""', new_string: "\"SentryOrg\": \"#{ENV['SENTRY_ORG']}\"" ) end if ENV['SENTRY_PROJECT_IOS'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SentryProjectIos": ""', new_string: "\"SentryProjectIos\": \"#{ENV['SENTRY_PROJECT_IOS']}\"" ) end if ENV['SENTRY_PROJECT_ANDROID'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SentryProjectAndroid": ""', new_string: "\"SentryProjectAndroid\": \"#{ENV['SENTRY_PROJECT_ANDROID']}\"" ) end if ENV['SENTRY_DSN_IOS'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SentryDsnIos": ""', new_string: "\"SentryDsnIos\": \"#{ENV['SENTRY_DSN_IOS']}\"" ) end if ENV['SENTRY_DSN_ANDROID'] find_replace_string( path_to_file: './dist/assets/config.json', old_string: '"SentryDsnAndroid": ""', new_string: "\"SentryDsnAndroid\": \"#{ENV['SENTRY_DSN_ANDROID']}\"" ) end end def link_sentry_android() if ENV['SENTRY_ENABLED'] == 'true' File.open('../android/sentry.properties', 'w+') do |f| UI.message('Creating sentry.properties from environment') f.write( 'defaults.url=https://sentry.io/\n'\ "defaults.org=#{ENV['SENTRY_ORG']}\n"\ "defaults.project=#{ENV['SENTRY_PROJECT_ANDROID']}\n"\ "auth.token=#{ENV['SENTRY_AUTH_TOKEN']}\n"\ "cli.executable=${File.expand_path('node_modules/sentry-cli-binary/bin/sentry-cli')}\n" ) end else UI.message('Not creating sentry.properties because Sentry is disabled') end end