diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..48fee14
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "build_options_helper"]
+ path = xcode/config_generator/build_options_helper
+ url = https://github.com/petropavel13/build_options_helper
diff --git a/android_hooks/pre-push b/android_hooks/pre-push
deleted file mode 100755
index cc5cdce..0000000
--- a/android_hooks/pre-push
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-
-echo "Pre push static analysis"
-
-output=$(./gradlew staticAnalysis --daemon 2>&1)
-
-status=$?
-
-if [ "$status" = 0 ] ; then
- exit 0
-else
- build_date=$(date +'%Y-%m-%d_%T')
- file_name="build_$build_date"
- folder_name="./build_log/"
- file_path="${folder_name}${file_name}"
- mkdir -p "$folder_name"
- echo "$output" >> "$file_path"
- echo "Pre push static failed. Full log path: ${file_path}"
- exit 1
-fi
diff --git a/gradle/installGitHooks.gradle b/gradle/installGitHooks.gradle
deleted file mode 100644
index 8f1ebc4..0000000
--- a/gradle/installGitHooks.gradle
+++ /dev/null
@@ -1,7 +0,0 @@
-task installGitHooks(type: Copy) {
- from new File(buildScriptsDir, 'android_hooks')
- into { new File(rootProject.rootDir, '.git/hooks') }
- fileMode 0777
-}
-
-tasks.getByPath(':app:preBuild').dependsOn installGitHooks
diff --git a/lint/lint.xml b/lint/lint.xml
index c834f09..57a80e9 100644
--- a/lint/lint.xml
+++ b/lint/lint.xml
@@ -8,12 +8,13 @@
-
-
+
+
+
diff --git a/proguard/rules/components.pro b/proguard/rules/components.pro
index 830b721..5bf7020 100644
--- a/proguard/rules/components.pro
+++ b/proguard/rules/components.pro
@@ -1,2 +1,2 @@
# View controllers are created through reflection.
--keep class ** extends ru.touchin.roboswag.components.navigation.viewcontrollers.ViewController { *; }
+-keep class ** extends ru.touchin.roboswag.navigation_viewcontroller.viewcontrollers.ViewController { *; }
diff --git a/xcode/.swiftlint.yml b/xcode/.swiftlint.yml
index 4bbc84c..d502145 100644
--- a/xcode/.swiftlint.yml
+++ b/xcode/.swiftlint.yml
@@ -239,6 +239,18 @@ custom_rules:
message: "Use сontentView instead of self for addSubview or addSubviews methods in cell."
severity: error
+ redundant_type_annotation_bool:
+ name: "Redundant type annotation for Bool"
+ regex: '((var|let)) *\w+ *((: *Bool *=)|((\w| |<|>|:)*= *BehaviorRelay\( *value *:)) *((true)|(false))'
+ message: "Using a type annotation for Bool is redundant."
+ severity: error
+
+ parameter_repetition:
+ name: "Parameter repetition"
+ regex: 'func ((\w+([A-Z]\w+))|(\w+)) *(<[^>]+>)? *\( *(?i)(\3|\4):'
+ message: "The parameter name is actually used in the function name. Use _ instead."
+ severity: error
+
# Rx
unused_map_parameter:
diff --git a/xcode/commonFastfile b/xcode/commonFastfile
index 382a448..d903469 100644
--- a/xcode/commonFastfile
+++ b/xcode/commonFastfile
@@ -87,7 +87,10 @@ end
private_lane :addShield do |options|
buildNumber = options[:buildNumber]
- buildDescription = options[:xcconfig_name].scan(/\p{Upper}/)[1..2].join
+ buildDescription = options[:xcconfig_name] # EnterpriseCustomerDev1WithoutSSLPinningRelease
+ .split(/(?=[A-Z])/) # -> ["Enterprise", "Customer", "Dev1", "Without", "S", "S", "L", "Pinning", "Release"]
+ .map { |v| v.gsub(/[[:lower:]]+/, "") }[1..2] # -> ["E", "C", "D1", "W", "S", "S", "L", "P", "R"] -> ["C", "D1"]
+ .join # -> "CD1"
begin
add_badge(
@@ -108,11 +111,7 @@ private_lane :buildConfiguration do |options|
options[:xcconfig_name] = lane_name
configuration_type = Touchlane::ConfigurationType.from_lane_name(lane_name)
- configuration = get_configuration_for_type(configuration_type.type)
-
- options = configuration.to_options
- .merge(get_keychain_options(options))
- .merge(options)
+ options = fill_up_options_using_configuration_type(options, configuration_type)
openKeychain(options)
@@ -136,13 +135,13 @@ private_lane :buildConfiguration do |options|
if !(options[:uploadToFabric] || options[:uploadToAppStore])
options[:skip_package_ipa] = true
- syncCodeSigning(options)
+ sync_code_signing_using_options(options)
buildArchive(options) # check build failures and static analysis
end
if options[:uploadToFabric]
- syncCodeSigning(options)
+ sync_code_signing_using_options(options)
addShield(options)
buildArchive(options)
@@ -153,7 +152,7 @@ private_lane :buildConfiguration do |options|
options[:compileBitcode] = options[:compileBitcode].nil? ? true : options[:compileBitcode]
options[:include_symbols] = options[:include_symbols].nil? ? true : options[:include_symbols]
- syncCodeSigning(options)
+ sync_code_signing_using_options(options)
buildArchive(options)
uploadToAppStore(options)
@@ -206,23 +205,11 @@ lane :createPushCertificate do |options|
)
end
-lane :syncCodeSigning do |options|
- match(
- app_identifier: options[:app_identifier],
- username: options[:username] || options[:apple_id],
- team_id: options[:team_id],
- type: options[:type],
- readonly: options[:readonly].nil? ? true : options[:readonly],
- storage_mode: "git",
- git_url: options[:git_url],
- git_branch: "fastlane_certificates",
- shallow_clone: true,
- clone_branch_directly: true,
- keychain_name: options[:keychain_name],
- keychain_password: options[:keychain_password],
- skip_docs: true,
- platform: "ios"
- )
+lane :SyncCodeSigning do |options|
+ configuration_type = Touchlane::ConfigurationType.from_type(options[:type])
+ options = fill_up_options_using_configuration_type(options, configuration_type)
+
+ sync_code_signing_using_options(options)
end
lane :SyncSymbols do |options|
@@ -346,6 +333,32 @@ lane :ManuallyUpdateCodeSigning do |options|
end
+def sync_code_signing_using_options(options)
+ match(
+ app_identifier: options[:app_identifier],
+ username: options[:username] || options[:apple_id],
+ team_id: options[:team_id],
+ type: options[:type],
+ readonly: options[:readonly].nil? ? true : options[:readonly],
+ storage_mode: "git",
+ git_url: options[:git_url],
+ git_branch: "fastlane_certificates",
+ shallow_clone: true,
+ clone_branch_directly: true,
+ keychain_name: options[:keychain_name],
+ keychain_password: options[:keychain_password],
+ skip_docs: true,
+ platform: "ios"
+ )
+end
+
+def fill_up_options_using_configuration_type(options, configuration_type)
+ configuration = get_configuration_for_type(configuration_type.type)
+
+ configuration.to_options
+ .merge(get_keychain_options(options))
+ .merge(options)
+end
def get_keychain_options(options)
keychain_name = options[:keychain_name]
diff --git a/xcode/config_generator/build_options_helper b/xcode/config_generator/build_options_helper
new file mode 160000
index 0000000..3f81529
--- /dev/null
+++ b/xcode/config_generator/build_options_helper
@@ -0,0 +1 @@
+Subproject commit 3f81529c1425a74f43fe84fe8befffd81a442cc7
diff --git a/xcode/config_generator/custom_settings.json b/xcode/config_generator/custom_settings.json
deleted file mode 100644
index a190324..0000000
--- a/xcode/config_generator/custom_settings.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "targets": [
- {
- "YOUR_TARGET_NAME": {
- "Standard": {
- "PROVISIONING_PROFILE_SPECIFIER": "",
- "PRODUCT_BUNDLE_IDENTIFIER": "",
- "CODE_SIGN_ENTITLEMENTS": ""
- },
-
- "Enterprise": {
- "PROVISIONING_PROFILE_SPECIFIER": "",
- "PRODUCT_BUNDLE_IDENTIFIER": "",
- "CODE_SIGN_ENTITLEMENTS": ""
- },
-
- "AppStore": {
- "DEVELOPMENT_TEAM": "",
- "PRODUCT_BUNDLE_IDENTIFIER": "",
- "CODE_SIGN_ENTITLEMENTS": ""
- }
- }
- }
- ]
-}
diff --git a/xcode/config_generator/example_settings.yaml b/xcode/config_generator/example_settings.yaml
new file mode 100644
index 0000000..608981a
--- /dev/null
+++ b/xcode/config_generator/example_settings.yaml
@@ -0,0 +1,27 @@
+targets:
+ TestProject:
+ development:
+ PRODUCT_BUNDLE_IDENTIFIER: "ru.touchin.testproject"
+ PROVISIONING_PROFILE_SPECIFIER: "TestProjectDev"
+ CODE_SIGN_ENTITLEMENTS: "TestProject/Standard.entitlements"
+ enterprise:
+ PRODUCT_BUNDLE_IDENTIFIER: "com.touchin.testproject"
+ PROVISIONING_PROFILE_SPECIFIER: "TestProjectEnterprise"
+ CODE_SIGN_ENTITLEMENTS: "TestProject/Enterprise.entitlements"
+ appstore:
+ PRODUCT_BUNDLE_IDENTIFIER: "ru.customer.domain"
+ PROVISIONING_PROFILE_SPECIFIER: "TestProjectAppStore"
+ CODE_SIGN_ENTITLEMENTS: "TestProject/Production.entitlements"
+
+types:
+ development:
+ apple_id: "apple@touchin.ru"
+ team_id: "**********"
+ itc_team_id: "**********"
+ enterprise:
+ apple_id: "enterpriseapple@touchin.ru"
+ team_id: "**********"
+ appstore:
+ apple_id: "apple@touchin.ru"
+ team_id: "**********"
+ itc_team_id: "**********"
\ No newline at end of file
diff --git a/xcode/config_generator/gen_configurations.py b/xcode/config_generator/gen_configurations.py
deleted file mode 100644
index 22845ed..0000000
--- a/xcode/config_generator/gen_configurations.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from __future__ import unicode_literals # python 2/3 support
-
-from itertools import chain
-import json
-
-distribution_options = ["Enterprise", "Standard"]
-server_type_options = ["Mock", "Touchin", "Customer"]
-server_environment_options = ["Dev", "Test", "Stage", "Prod"]
-ssl_pinning_options = ["WithSSLPinning", "WithoutSSLPinning"]
-build_type_options = ["Debug", "Release"]
-
-all_options = [
- distribution_options,
- server_type_options,
- server_environment_options,
- ssl_pinning_options,
- build_type_options
-]
-
-def combine_string_with_options(all_options, string="", applied_options=[]):
- if len(all_options) == 0:
- yield string, applied_options
- return
-
- for current_option in chain.from_iterable(all_options[:1]):
- for result_tuple in combine_string_with_options(all_options[1:], string + current_option, applied_options + [current_option]):
- yield result_tuple
-
- yield ("AppStoreRelease", ['AppStore', 'Customer', 'Prod', 'WithSSLPinning', 'Release'])
-
-def make_config_dict(args):
- config_name, applied_options = args
-
- if "Enterprise" in applied_options:
- account_type = "Enterprise"
- elif "Standard" in applied_options:
- account_type = "Standard"
- else:
- account_type = "AppStore"
-
- if "Debug" in applied_options:
- build_type = "debug"
- elif "AppStore" in applied_options:
- build_type = "appstore"
- else:
- build_type = "release"
-
- return {
- "name": config_name,
- "build_type": build_type,
- "account_type": account_type,
- "xcconfig_options": [
- {
- "key": "SWIFT_ACTIVE_COMPILATION_CONDITIONS",
- "value": " ".join(map(lambda option: option.upper(), applied_options))
- },
- {
- "key": "DEBUG_INFORMATION_FORMAT",
- "value": "dwarf" if "Debug" in applied_options else "dwarf-with-dsym"
- },
- {
- "key": "VALIDATE_PRODUCT",
- "value": "NO" if "Debug" in applied_options else "YES"
- },
- {
- "key": "ENABLE_TESTABILITY",
- "value": "YES" if "Debug" in applied_options else "NO"
- },
- {
- "key": "CODE_SIGN_IDENTITY",
- "value": "iPhone Developer" if account_type == "Standard" else "iPhone Distribution"
- },
- {
- "key": "GCC_OPTIMIZATION_LEVEL",
- "value": "0" if "Debug" in applied_options else "s"
- },
- {
- "key": "SWIFT_OPTIMIZATION_LEVEL",
- "value": "-Onone" if "Debug" in applied_options else "-O"
- },
- {
- "key": "SWIFT_COMPILATION_MODE",
- "value": "singlefile" if "Debug" in applied_options else "wholemodule"
- }
- ]
- }
-
-
-config_dicts = map(make_config_dict, combine_string_with_options(all_options))
-
-print(json.dumps({"configurations": config_dicts}, indent=4))
diff --git a/xcode/config_generator/render_xcconfigs.rb b/xcode/config_generator/render_xcconfigs.rb
old mode 100644
new mode 100755
index dbe8d84..64d6b8e
--- a/xcode/config_generator/render_xcconfigs.rb
+++ b/xcode/config_generator/render_xcconfigs.rb
@@ -1,110 +1,152 @@
require 'json'
require 'mustache'
+require 'yaml'
+
+# Usage: render_xcconfigs.rb
+#
+# Result: Adds .xcconfig files to $configs_folder_name directory.
+# Files are only being added and changed, not removed!
+# It is recommended to remove old .xcconfig files before running this script.
+
# Constants
$configs_folder_name = "TargetConfigurations"
-$standard_dev_team = "D4HA43V467"
-$enterprise_dev_team = "228J5MMU7S"
-$standard_bundle_prefix = "ru.touchin."
-$enterprise_bundle_prefix = "com.touchin."
-$bundle_id_key = "PRODUCT_BUNDLE_IDENTIFIER"
-# create config directory if needed
+class String
+ def in_current_dir
+ "#{__dir__}/#{self}"
+ end
+end
+
+# Input files paths
+configurations_file_path = ARGV[0]
+temp_configs_data_file_path = "configs_data.json".in_current_dir
+generator_path = "build_options_helper/helper.py".in_current_dir
+template_path = "target_xcconfig.mustache".in_current_dir
+build_parameters_path = ARGV[1] || "build_parameters.yaml".in_current_dir
+
+# Create config directory if needed
Dir.mkdir($configs_folder_name) unless Dir.exist?($configs_folder_name)
-# call python script and generate configs to config file
-system("python gen_configurations.py > configs_data.json")
+# Call python script and generate configs to config file
+system("python #{generator_path} -bp #{build_parameters_path} -o #{__dir__} -r ios_build_settings -p ios")
+# Open settings, configurations and template files
+target_xcconfig_tempate = File.read(template_path)
+$configurations = YAML.load(File.open(configurations_file_path))
+$config_types = $configurations["types"]
-# open settings + template file
-settings = JSON.load(File.open("custom_settings.json"))
-target_xcconfig_tempate = File.read("target_xcconfig.mustache")
+# Set global property
+targets = $configurations["targets"]
-
-# set global property
-targets = settings["targets"]
-
-# make tuple of key and value become mustache template element
+# Make tuple of key and value become mustache template element
def config_option(key, value)
return { "key" => key, "value" => value }
end
-# return empty array or generated dev team hash
-def generate_development_team(development_team_key, account_type)
- team_value = account_type == "Standard" ? $standard_dev_team : $enterprise_dev_team
+# Maps lane prefix to distribution type
+def distribution_type_of(account_type)
+ case account_type
+ when "Standard"
+ "development"
+ when "Enterprise"
+ "enterprise"
+ when "AppStore"
+ "appstore"
+ else
+ raise "Error: Unsupported distribution type #{account_type}"
+ end
+end
+
+# Fetch development team from build configuration
+def fetch_development_team(development_team_key, distribution_type)
+ current_config = $config_types[distribution_type]
+ team_value = current_config["team_id"]
return config_option(development_team_key, team_value)
end
-# return empty array or generated provisioning profile hash
-def generate_provisioning_profile(provisioning_key, bundle_id, account_type)
- if account_type == "AppStore"
- app_store_profiile = "match AppStore " + bundle_id
- return config_option(provisioning_key, app_store_profiile)
- else
- return config_option(provisioning_key, bundle_id)
- end
+# Return empty array or generated provisioning profile hash
+def generate_provisioning_profile(provisioning_key, bundle_id, distribution_type)
+ case distribution_type
+ when "appstore"
+ app_store_profile = "match AppStore " + bundle_id
+ config_option(provisioning_key, app_store_profile)
+ else
+ config_option(provisioning_key, bundle_id)
+ end
end
-def generate_bundle_id(target_name, account_type)
- bundle_id_prefix = account_type == "Standard" ? $standard_bundle_prefix : $enterprise_bundle_prefix
- bundle_id = bundle_id_prefix + target_name
- return config_option($bundle_id_key, bundle_id)
+def generate_google_service_info_plist_path(google_service_info_plist_key, target_name, distribution_type)
+ google_service_info_plist_path = target_name + "/Resources/"
+
+ path_suffix = case distribution_type
+ when "development"
+ "Standard-GoogleService-Info.plist"
+ when "enterprise"
+ "Enterprise-GoogleService-Info.plist"
+ else
+ "AppStore-GoogleService-Info.plist"
+ end
+
+ return config_option(google_service_info_plist_key, google_service_info_plist_path + path_suffix)
end
-# generate missing properties if needed
-def generate_missing_properties(target_name, properties, account_type)
+# Generate missing properties if needed
+def generate_missing_properties(target_name, properties, distribution_type)
result = []
development_team_key = "DEVELOPMENT_TEAM"
provisioning_key = "PROVISIONING_PROFILE_SPECIFIER"
+ google_service_info_plist_key = "GOOGLE_SERVICE_INFO_PLIST_PATH"
+ bundle_id_key = "PRODUCT_BUNDLE_IDENTIFIER"
- unless properties.key?($bundle_id_key)
- bundle_id_config = generate_bundle_id(target_name, account_type)
- bundle_id = bundle_id_config["value"]
- result.append(bundle_id_config)
- else
- bundle_id = properties[$bundle_id_key]
+ # Bundle_id_key should be among the properties (required by fastlane)
+ unless properties.key?(bundle_id_key)
+ raise "#{target_name}: Could not find #{bundle_id_key} for #{distribution_type}"
end
unless properties.key?(development_team_key)
- result.append(generate_development_team(development_team_key, account_type))
+ result.append(fetch_development_team(development_team_key, distribution_type))
end
unless properties.key?(provisioning_key)
- result.append(generate_provisioning_profile(provisioning_key, bundle_id, account_type))
+ result.append(generate_provisioning_profile(provisioning_key, properties[bundle_id_key], distribution_type))
+ end
+
+ unless properties.key?(google_service_info_plist_key)
+ result.append(generate_google_service_info_plist_path(google_service_info_plist_key, target_name, distribution_type))
end
return result
end
-# run through all target in project
-targets.each do |target|
+# Run through all target in project
+targets.each do |target_name, target|
- # need open everytime, because script make some changes only for this target
- configs = JSON.load(File.open("configs_data.json"))["configurations"]
+ # Need open everytime, because script make some changes only for this target
+ configs = JSON.load(File.open(temp_configs_data_file_path))
- # run through all configs
+ # Run through all configs
configs.each do |config|
- # take default values
- account_type = config["account_type"]
- target_name = target.keys.first
- properties = target[target_name][account_type]
+ # Take default values
+ distribution_type = distribution_type_of(config["account_type"])
+ properties = target[distribution_type]
- # add properties from settings file
+ # Add properties from settings file
properties.each do |key, value|
config["xcconfig_options"].append(config_option(key, value))
end
- # add missing properties if needed
- config["xcconfig_options"].concat(generate_missing_properties(target_name, properties, account_type))
+ # Add missing properties if needed
+ config["xcconfig_options"].concat(generate_missing_properties(target_name, properties, distribution_type))
- # create settings pack
+ # Create settings pack
config_data = {
"target_name": target_name,
"configuration": config
}
- # create file for every setting in loop
+ # Create file for every setting in loop
File.open($configs_folder_name + "/" + target_name + config["name"] + ".xcconfig", 'w') { |file|
file.puts(Mustache.render(target_xcconfig_tempate, config_data))
}
@@ -112,5 +154,5 @@ targets.each do |target|
end
-# remove config file, it's trash
-File.delete("configs_data.json") if File.exist?("configs_data.json")
+# Remove config file, it's trash
+File.delete(temp_configs_data_file_path) if File.exist?(temp_configs_data_file_path)
diff --git a/xcode/fastlane/touchlane/lib/configuration.rb b/xcode/fastlane/touchlane/lib/configuration.rb
index a12c764..02cc4d3 100644
--- a/xcode/fastlane/touchlane/lib/configuration.rb
+++ b/xcode/fastlane/touchlane/lib/configuration.rb
@@ -13,18 +13,19 @@ module Touchlane
attr_reader :type, :app_identifier, :apple_id, :team_id, :itc_team_id
def self.from_file(path, type)
- hash_of_types = load_hash_of_types_from_file(path)
- attrs_hash = hash_of_types[type]
+ configuration_hash = load_configuration_from_file(path)
+ attrs_hash = configuration_hash["types"][type]
+ identifiers = get_app_identifiers_from_configuration_hash(configuration_hash, type)
unless attrs_hash
raise "There is no configuration with type #{type}. Available types: #{attrs_hash.keys}"
else
config_type = Touchlane::ConfigurationType.from_type(type)
- new(config_type, attrs_hash["app_identifier"], attrs_hash["apple_id"], attrs_hash["team_id"], attrs_hash["itc_team_id"])
+ new(config_type, identifiers, attrs_hash["apple_id"], attrs_hash["team_id"], attrs_hash["itc_team_id"])
end
end
- def self.load_hash_of_types_from_file(path)
+ def self.load_configuration_from_file(path)
unless File.exists? path
raise "Unable to load configurations from file at #{path}"
else
@@ -32,7 +33,14 @@ module Touchlane
end
end
- private_class_method :new, :load_hash_of_types_from_file
+ def self.get_app_identifiers_from_configuration_hash(configuration_hash, type)
+ identifier_key = "PRODUCT_BUNDLE_IDENTIFIER"
+ configuration_hash["targets"].collect do |target, types|
+ types[type][identifier_key] or raise "#{target}: There is no #{identifier_key} field in #{type}"
+ end
+ end
+
+ private_class_method :new, :load_configuration_from_file, :get_app_identifiers_from_configuration_hash
def to_options
{