Merge branch 'master' into static/multi_module_static
# Conflicts: # gradle/commonStaticAnalysis.gradle
This commit is contained in:
commit
89a89e38c4
|
|
@ -0,0 +1,20 @@
|
|||
#!/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
|
||||
|
|
@ -7,7 +7,7 @@ configurations {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
apigenerator 'ru.touchin:api-generator:1.2.9'
|
||||
apigenerator 'ru.touchin:api-generator:1.4.0-beta1'
|
||||
}
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ configurations {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
apigeneratorKotlinServer 'ru.touchin:api-generator:1.3.2'
|
||||
apigeneratorKotlinServer 'ru.touchin:api-generator:1.4.0-alpha1'
|
||||
}
|
||||
|
||||
task generateApiModelsKotlinServer doLast {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
android {
|
||||
defaultConfig {
|
||||
setProperty(
|
||||
"archivesBaseName",
|
||||
"${project.android.defaultConfig.applicationId}" +
|
||||
"-" +
|
||||
"${project.android.defaultConfig.versionName}" +
|
||||
"-" +
|
||||
"${project.android.defaultConfig.versionCode}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
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
|
||||
|
|
@ -267,5 +267,6 @@
|
|||
<issue id="ViewHolder" severity="ignore"/>
|
||||
<issue id="WebViewLayout" severity="ignore"/>
|
||||
<issue id="TypographyEllipsis" severity="ignore"/>
|
||||
<issue id="PermissionImpliesUnsupportedChromeOsHardware" severity="ignore"/>
|
||||
|
||||
</lint>
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@
|
|||
-include rules/crashlytics.pro
|
||||
-include rules/glide.pro
|
||||
-include rules/kaspersky.pro
|
||||
-include rules/appsflyer.pro
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
-dontwarn com.google.android.gms.iid.**
|
||||
-keep class com.appsflyer.** { *; }
|
||||
-dontwarn android.app.job.JobParameters
|
||||
-dontwarn com.android.installreferrer.**
|
||||
-dontwarn com.appsflyer.**
|
||||
|
|
@ -60,6 +60,7 @@ excluded:
|
|||
- Carthage
|
||||
- Pods
|
||||
- Generated
|
||||
- Localization
|
||||
|
||||
line_length: 128
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
excluded-resources:
|
||||
- Generated/
|
||||
- Resources/Localization
|
||||
- Carthage/
|
||||
- Pods/
|
||||
- FormattingService.swift
|
||||
|
|
@ -1,12 +1,29 @@
|
|||
file_name=$1
|
||||
file_link=$2
|
||||
folder=$3
|
||||
flag_of_delete=$4
|
||||
|
||||
folder="Downloads"
|
||||
file_path="./${folder}/${file_name}"
|
||||
readonly key_of_delete="--remove-cached"
|
||||
readonly default_folder="./Downloads"
|
||||
|
||||
if [[ ${folder} = ${key_of_delete} ]]; then
|
||||
folder="${default_folder}"
|
||||
flag_of_delete="${key_of_delete}"
|
||||
fi
|
||||
|
||||
if ! [ -n "$folder" ]; then
|
||||
folder="${default_folder}"
|
||||
fi
|
||||
|
||||
file_path="${folder}/${file_name}"
|
||||
|
||||
if [[ ${flag_of_delete} = ${key_of_delete} ]]; then
|
||||
rm ${file_path}
|
||||
fi
|
||||
|
||||
# make folder if not exist
|
||||
if ! [ -e ${folder} ]; then
|
||||
mkdir ${folder}
|
||||
mkdir -p ${folder}
|
||||
fi
|
||||
|
||||
# download file if not downloaded
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?php
|
||||
$PROJECT_NAME = $argv[1];
|
||||
$PRODUCT_NAME = $argv[1];
|
||||
$COMMON_STRINGS_PATH = $argv[2];
|
||||
|
||||
function createFolder($path) {
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
$localization = './'.$PROJECT_NAME.'/Resources/Localization/';
|
||||
$localization = './'.$PRODUCT_NAME.'/Resources/Localization/';
|
||||
|
||||
$baseFile = file_get_contents(array_pop(glob($COMMON_STRINGS_PATH.'/default*.json')));
|
||||
$baseJson = json_decode($baseFile, true);
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
'// swiftlint:disable line_length'.PHP_EOL.
|
||||
'// swiftlint:disable file_length'.PHP_EOL.
|
||||
'// swiftlint:disable identifier_name'.PHP_EOL.PHP_EOL.
|
||||
'extension String {'.PHP_EOL;
|
||||
'public extension String {'.PHP_EOL;
|
||||
foreach ($json as $key=>$value) {
|
||||
$value_without_linefeed = preg_replace("/\r|\n/", " ", $value);
|
||||
$ios_swift_strings .= "\t/// ".$value_without_linefeed."\n\t".'static let '.preg_replace_callback('/_(.?)/', function ($m) { return strtoupper($m[1]); }, $key).' = NSLocalizedString("'.$key.'", comment: "")'."\n".PHP_EOL;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,189 @@
|
|||
# source: https://github.com/PaulTaykalo/swift-scripts/blob/master/unused.rb
|
||||
#!/usr/bin/ruby
|
||||
#encoding: utf-8
|
||||
require 'yaml'
|
||||
require 'optparse'
|
||||
|
||||
Encoding.default_external = Encoding::UTF_8
|
||||
Encoding.default_internal = Encoding::UTF_8
|
||||
|
||||
class Item
|
||||
def initialize(file, line, at)
|
||||
@file = file
|
||||
@line = line
|
||||
@at = at + 1
|
||||
if match = line.match(/(func|let|var|class|enum|struct|protocol)\s+(\w+)/)
|
||||
@type = match.captures[0]
|
||||
@name = match.captures[1]
|
||||
end
|
||||
end
|
||||
|
||||
def modifiers
|
||||
return @modifiers if @modifiers
|
||||
@modifiers = []
|
||||
if match = @line.match(/(.*?)#{@type}/)
|
||||
@modifiers = match.captures[0].split(" ")
|
||||
end
|
||||
return @modifiers
|
||||
end
|
||||
|
||||
def name
|
||||
@name
|
||||
end
|
||||
|
||||
def file
|
||||
@file
|
||||
end
|
||||
|
||||
def to_s
|
||||
serialize
|
||||
end
|
||||
def to_str
|
||||
serialize
|
||||
end
|
||||
|
||||
def full_file_path
|
||||
Dir.pwd + '/' + @file
|
||||
end
|
||||
|
||||
def serialize
|
||||
"#{@file} has unused \"#{@type.to_s} #{@name.to_s}\""
|
||||
end
|
||||
def to_xcode
|
||||
"#{full_file_path}:#{@at}:0: warning: #{@type.to_s} #{@name.to_s} is unused"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
class Unused
|
||||
def find
|
||||
items = []
|
||||
unused_warnings = []
|
||||
|
||||
regexps = parse_arguments
|
||||
|
||||
all_files = Dir.glob("**/*.swift").reject do |path|
|
||||
File.directory?(path)
|
||||
end
|
||||
|
||||
all_files.each { |my_text_file|
|
||||
file_items = grab_items(my_text_file)
|
||||
file_items = filter_items(file_items)
|
||||
|
||||
non_private_items, private_items = file_items.partition { |f| !f.modifiers.include?("private") && !f.modifiers.include?("fileprivate") }
|
||||
items += non_private_items
|
||||
|
||||
# Usage within the file
|
||||
if private_items.length > 0
|
||||
unused_warnings += find_usages_in_files([my_text_file], [], private_items, regexps)
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
xibs = Dir.glob("**/*.xib")
|
||||
storyboards = Dir.glob("**/*.storyboard")
|
||||
|
||||
unused_warnings += find_usages_in_files(all_files, xibs + storyboards, items, regexps)
|
||||
|
||||
if unused_warnings.length > 0
|
||||
# show warning
|
||||
puts "Unused Code Warning!: warning: Total Count #{unused_warnings.length}"
|
||||
puts "#{unused_warnings.map { |e| e.to_xcode}.join("\n")}"
|
||||
# write log
|
||||
File.open("UnusedLog.txt", "w") do |file|
|
||||
file.write("Unused code warnings count: #{unused_warnings.length}\n\n")
|
||||
file.write("#{unused_warnings.map { |e| e.serialize }.join("\n")}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def parse_arguments
|
||||
resources = []
|
||||
|
||||
options = {}
|
||||
OptionParser.new do |opts|
|
||||
options[:exclude] = []
|
||||
|
||||
opts.on("-c", "--config=FileName") { |c| options[:config] = c }
|
||||
opts.on("-i", "--exclude [a, b, c]", Array) { |i| options[:exclude] += i if !i.nil? }
|
||||
|
||||
end.parse!
|
||||
|
||||
# find --config file
|
||||
if !options[:config].nil?
|
||||
fileName = options[:config]
|
||||
resources += YAML.load_file(fileName).fetch("excluded-resources")
|
||||
elsif
|
||||
puts "---------\n Warning: Config file is not provided \n---------"
|
||||
end
|
||||
|
||||
# find --exclude files
|
||||
if !options[:exclude].nil?
|
||||
resources += options[:exclude]
|
||||
end
|
||||
|
||||
# create and return Regexp
|
||||
resources.map { |r| Regexp.new(r) }
|
||||
end
|
||||
|
||||
def grab_items(file)
|
||||
lines = File.readlines(file).map {|line| line.gsub(/^\s*\/\/.*/, "") }
|
||||
items = lines.each_with_index.select { |line, i| line[/(func|let|var|class|enum|struct|protocol)\s+\w+/] }.map { |line, i| Item.new(file, line, i)}
|
||||
end
|
||||
|
||||
def filter_items(items)
|
||||
items.select { |f|
|
||||
!f.name.start_with?("test") && !f.modifiers.include?("@IBAction") && !f.modifiers.include?("override") && !f.modifiers.include?("@objc") && !f.modifiers.include?("@IBInspectable")
|
||||
}
|
||||
end
|
||||
|
||||
# remove files, that maches excluded Regexps array
|
||||
def ignore_files_with_regexps(files, regexps)
|
||||
files.select { |f| regexps.all? { |r| r.match(f.file).nil? } }
|
||||
end
|
||||
|
||||
def find_usages_in_files(files, xibs, items_in, regexps)
|
||||
items = items_in
|
||||
usages = items.map { |f| 0 }
|
||||
files.each { |file|
|
||||
lines = File.readlines(file).map {|line| line.gsub(/^[^\/]*\/\/.*/, "") }
|
||||
words = lines.join("\n").split(/\W+/)
|
||||
words_arrray = words.group_by { |w| w }.map { |w, ws| [w, ws.length] }.flatten
|
||||
|
||||
wf = Hash[*words_arrray]
|
||||
|
||||
items.each_with_index { |f, i|
|
||||
usages[i] += (wf[f.name] || 0)
|
||||
}
|
||||
# Remove all items which has usage 2+
|
||||
indexes = usages.each_with_index.select { |u, i| u >= 2 }.map { |f, i| i }
|
||||
|
||||
# reduce usage array if we found some functions already
|
||||
indexes.reverse.each { |i| usages.delete_at(i) && items.delete_at(i) }
|
||||
}
|
||||
|
||||
xibs.each { |xib|
|
||||
lines = File.readlines(xib).map {|line| line.gsub(/^\s*\/\/.*/, "") }
|
||||
full_xml = lines.join(" ")
|
||||
classes = full_xml.scan(/(class|customClass)="([^"]+)"/).map { |cd| cd[1] }
|
||||
classes_array = classes.group_by { |w| w }.map { |w, ws| [w, ws.length] }.flatten
|
||||
|
||||
wf = Hash[*classes_array]
|
||||
|
||||
items.each_with_index { |f, i|
|
||||
usages[i] += (wf[f.name] || 0)
|
||||
}
|
||||
# Remove all items which has usage 2+
|
||||
indexes = usages.each_with_index.select { |u, i| u >= 2 }.map { |f, i| i }
|
||||
|
||||
# reduce usage array if we found some functions already
|
||||
indexes.reverse.each { |i| usages.delete_at(i) && items.delete_at(i) }
|
||||
|
||||
}
|
||||
|
||||
items = ignore_files_with_regexps(items, regexps)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Unused.new.find
|
||||
|
|
@ -6,4 +6,4 @@ link="https://dl.bintray.com/touchin/touchin-tools/ru/touchin/api-generator/${VE
|
|||
. build-scripts/xcode/aux_scripts/download_file.sh ${FILE_NAME} ${link}
|
||||
|
||||
# execute api generator
|
||||
java -jar "Downloads/${FILE_NAME}" generate-client-code --output-language SWIFT --specification-path common/api --output-path ${PROJECT_NAME}/Generated --single-file true
|
||||
java -jar "Downloads/${FILE_NAME}" generate-client-code --output-language SWIFT --specification-path common/api --output-path ${PRODUCT_NAME}/Generated --single-file true
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
LOCALIZATION_PATH="${PROJECT_NAME}/Resources/Localization"
|
||||
LOCALIZATION_PATH="${PRODUCT_NAME}/Resources/Localization"
|
||||
#first argument set strings folder path
|
||||
STRINGS_FOLDER=${1:-"common/strings"}
|
||||
|
||||
|
|
@ -13,4 +13,4 @@ if ! [ -e "${PROJECT_DIR}/${STRINGS_FOLDER}" ]; then
|
|||
fi
|
||||
|
||||
#second argument set strings script path
|
||||
php ${2:-build-scripts/xcode/aux_scripts/import_strings.php} ${PROJECT_NAME} ${STRINGS_FOLDER}
|
||||
php ${2:-build-scripts/xcode/aux_scripts/import_strings.php} ${PRODUCT_NAME} ${STRINGS_FOLDER}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
arguments=("$@")
|
||||
ignored_files=$(IFS=, ; echo "${arguments[*]}")
|
||||
|
||||
ruby ${PROJECT_DIR}/build-scripts/xcode/build_phases/Unused.rb --config ${PROJECT_DIR}/build-scripts/xcode/UnusedConfig.yml --exclude ${ignored_files}
|
||||
|
|
@ -9,6 +9,10 @@ private_lane :installDependencies do |options|
|
|||
sh("rm -rf #{podsReposPath}")
|
||||
end
|
||||
|
||||
if File.exists? "../Gemfile"
|
||||
bundle_install(path: "../.gem")
|
||||
end
|
||||
|
||||
if File.exists? "../Cartfile"
|
||||
begin
|
||||
carthage(command: "bootstrap", platform: "iOS")
|
||||
|
|
@ -20,7 +24,7 @@ private_lane :installDependencies do |options|
|
|||
end
|
||||
|
||||
cocoapods(
|
||||
repo_update: false
|
||||
repo_update: true
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -196,6 +200,76 @@ private_lane :openKeychain do |options|
|
|||
end
|
||||
end
|
||||
|
||||
lane :ManuallyUpdateCodeSigning do |options|
|
||||
# based on this article https://medium.com/@jonathancardoso/using-fastlane-match-with-existing-certificates-without-revoking-them-a325be69dac6
|
||||
require 'fastlane_core'
|
||||
require 'match'
|
||||
|
||||
conf = FastlaneCore::Configuration.create(Match::Options.available_options, {})
|
||||
conf.load_configuration_file("Matchfile")
|
||||
|
||||
git_url = conf.config_file_options[:git_url]
|
||||
shallow_clone = false
|
||||
branch = 'fastlane_certificates'
|
||||
|
||||
storage_conf = lambda do
|
||||
new_storage = Match::Storage.for_mode('git', { git_url: git_url, shallow_clone: shallow_clone, git_branch: branch, clone_branch_directly: false})
|
||||
new_storage.download
|
||||
return new_storage
|
||||
end
|
||||
|
||||
encryption_conf_for_storage = lambda do |stor|
|
||||
new_encryption = Match::Encryption.for_storage_mode('git', { git_url: git_url, working_directory: stor.working_directory})
|
||||
new_encryption.decrypt_files
|
||||
return new_encryption
|
||||
end
|
||||
|
||||
get_all_files = lambda do |stor|
|
||||
Dir[File.join(stor.working_directory, "**", "*.{cer,p12,mobileprovision}")]
|
||||
end
|
||||
|
||||
storage = storage_conf.call
|
||||
encryption = encryption_conf_for_storage.call(storage)
|
||||
old_files = get_all_files.call(storage)
|
||||
|
||||
sh("open #{storage.working_directory}")
|
||||
|
||||
# we are not using prompt() since it requires non-empty input which is not a case for Enter (\n)
|
||||
puts "Enter any key when you're done"
|
||||
STDIN.gets
|
||||
|
||||
encryption.encrypt_files
|
||||
|
||||
files_to_commit = get_all_files.call(storage)
|
||||
old_directory = storage.working_directory
|
||||
storage.save_changes!(files_to_commit: files_to_commit)
|
||||
|
||||
|
||||
# need to check, because saving changes with delete is another function (update repo if needed)
|
||||
files_diff = old_files - files_to_commit
|
||||
|
||||
# match can not work with both save/delete functionality `You can't provide both files_to_delete and files_to_commit right now`
|
||||
# to avoid this we use storage twice if needed
|
||||
|
||||
if files_diff.length > 0
|
||||
storage = storage_conf.call
|
||||
encryption = encryption_conf_for_storage.call(storage)
|
||||
|
||||
files_to_delete = files_diff.map do |file|
|
||||
old_file = file
|
||||
old_file.slice! old_directory
|
||||
new_file = File.join(storage.working_directory, old_file)
|
||||
File.delete(new_file) if File.exist?(new_file)
|
||||
file = new_file
|
||||
end
|
||||
|
||||
encryption.encrypt_files
|
||||
storage.save_changes!(files_to_delete: files_to_delete)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
def get_keychain_options(options)
|
||||
keychain_name = options[:keychain_name]
|
||||
keychain_password = options[:keychain_password]
|
||||
|
|
|
|||
Loading…
Reference in New Issue