Compare commits

...

282 Commits

Author SHA1 Message Date
PhilippFalchuk dd85251813 MAN-001 PR: added afisha and toolbar 2025-10-20 18:58:53 +03:00
Nikita Mikryukov 069396ecb8 Merge pull request 'Replaced Enterprise with AdHoc' (#28) from feature/adHoc_cert into master
Reviewed-on: #28
Reviewed-by: Vladimir Makarov <vladimir.makarov@noreply.localhost>
2025-04-04 16:08:39 +03:00
Nikita Mikryukov fce05b99ec added AdHoc type 2025-04-01 14:59:43 +03:00
Ivan Smolin efa00ff67b Merge pull request 'fix: You can't use 'build_number' and 'ipa' options in one run.' (#20) from fix/ipa_and_build_number_for_appstore into master
Reviewed-on: #20
2024-01-31 13:48:30 +03:00
Ivan Smolin 565279ef75 fix: You can't use 'build_number' and 'ipa' options in one run. 2024-01-31 13:47:24 +03:00
Ivan Smolin 66f4df9425 Merge pull request 'fix syntax issue in swiftlint script' (#19) from fix/syntax_issue_in_swiftlint_script into master
Reviewed-on: #19
2024-01-29 16:50:32 +03:00
Ivan Smolin 5a663334f0 fix syntax issue in swiftlint script 2024-01-29 16:40:50 +03:00
Ivan Smolin ccd4df9314 Merge pull request 'add SubmitForReview command lane' (#18) from feature/app_store_submit_for_review_command into master
Reviewed-on: #18
2024-01-29 16:28:02 +03:00
Ivan Smolin d900c5b9ad add SubmitForReview command lane 2024-01-26 14:58:40 +03:00
Ivan Smolin 1160ea6320 Merge pull request 'feature/separate_actions' (#17) from feature/separate_actions into master
Reviewed-on: #17
2024-01-22 13:19:19 +03:00
Ivan Smolin e732e16d21 separate SyncCodeSigning to multiple actions 2024-01-22 10:58:29 +03:00
Bogdan Terehov abe62fca64 Merge pull request 'fix: поправил ссылки в README.md' (#16) from fix/build_script_url into master
Reviewed-on: #16
2024-01-18 15:05:08 +03:00
Bogdan Terehov 7f7d535ca5 fix: поправил ссылки 2024-01-18 14:31:39 +03:00
Ivan Smolin e54d505272 Merge pull request 'fix errors during make init call' (#15) from feature/make_init_fixes into master
Reviewed-on: #15
2024-01-18 14:09:47 +03:00
Ivan Smolin 70c2899bf0 Merge pull request 'use xcodes for Xcode version selection' (#14) from feature/xcode_version_selection_via_xcodes into master
Reviewed-on: #14
2024-01-18 14:08:39 +03:00
Ivan Smolin 434c4f4e6a fix errors during make init call 2024-01-18 09:54:51 +03:00
Ivan Smolin e44811d1b7 remove unused actions and methods 2024-01-17 12:25:46 +03:00
Ivan Smolin eaad4027c6 use xcodes for Xcode version selection 2024-01-16 11:09:06 +03:00
Ivan Smolin 5be3987ea3 Merge pull request 'Shell scripts updates to cpd, api-generator and bootstrap' (#13) from feature/cpd_update into master
Reviewed-on: #13
2024-01-15 15:35:39 +03:00
Ivan Smolin f8865b3232 add --skip-lexical-errors for pmd cpd
report error on api generator run failure
add bootstrap scripts for code lint
2023-12-29 18:44:05 +05:00
Nikita Mikryukov 4dfed1b2a8 Merge pull request 'Updated repositories link' (#9) from fix/update_links into master
Reviewed-on: #9
2023-05-29 11:39:51 +03:00
Nikita Mikryukov c841e48516 changed https link to ssh 2023-05-29 09:55:50 +03:00
Nikita Mikryukov 3e249eae3d updated repositories link 2023-05-29 09:28:27 +03:00
Ivan Smolin 318e0ce021 Merge pull request 'exclude playground app from lint, add make gen command to Makefile' (#7) from feature/exclude_playground_app into master
Reviewed-on: #7
2023-05-24 14:37:43 +03:00
Ivan Smolin f1fe35d298 exclude playground app from lint, add make gen command to Makefile 2023-05-24 13:35:01 +03:00
Ivan Smolin 39109c6e60 Merge pull request 'Disable autocorrection by default, make script more independent of environment (SPM support)' (#6) from feature/swiftlint_script_spm_support into master
Reviewed-on: #6
2023-05-24 09:26:06 +03:00
Ivan Smolin 7d3f2794bc simplify temp file creation 2023-05-22 11:59:45 +03:00
Ivan Smolin b843196f3c Disable autocorrection by default, make script more independent of environment 2023-05-19 17:46:45 +03:00
Ivan Smolin 96f4d38bab Merge pull request 'update SwiftLint config to support latest 0.52.2 version features' (#5) from feature/update_swiftlint into master
Reviewed-on: #5
2023-05-19 16:33:34 +03:00
Ivan Smolin e3b688639f update SwiftLint config to support latest 0.52.2 version features 2023-05-17 16:15:22 +03:00
Vladimir Makarov 16b6523742 Merge pull request '`options[:appName]` for `get_google_services_plist_path` used' (#4) from fix/dsyms_uploading into master
Reviewed-on: #4
2023-05-04 22:53:24 +03:00
Vladimir Makarov bf2ee40721 `options[:appName]` for `get_google_services_plist_path` used 2023-05-04 21:42:57 +02:00
Vladimir Makarov cd8e8c60e4 Merge pull request 'Deprecated `:SyncSymbols` removed, `upload_symbols_to_crashlytics` moved to a common building step, `compileBitcode` removed' (#1) from feature/dsyms_uploading into master
Reviewed-on: #1
2023-04-19 16:19:42 +03:00
Vladimir Makarov 69928bb749 Deprecated `:SyncSymbols` removed, `upload_symbols_to_crashlytics` moved to a common building step, `compileBitcode` removed 2023-04-19 16:02:00 +03:00
Kirill Khoroshkov d6c818370f Merge branch 'codestyle/kotlin' into 'master'
Added kotlin codestyle

See merge request touchinstinct/BuildScripts!6
2023-04-13 14:40:14 +00:00
KirillKhoroshkov b50ced768e Added trailing comma 2023-04-01 19:37:48 +03:00
KirillKhoroshkov 7c5352e6c9 Edited README 2023-03-29 00:58:49 +03:00
KirillKhoroshkov 23fb4371b1 Edited README 2023-03-29 00:57:20 +03:00
KirillKhoroshkov 211020a30d Edited README 2023-03-28 15:52:48 +03:00
KirillKhoroshkov 4716bdb131 Edited README and removed the old scheme 2023-03-28 03:50:35 +03:00
KirillKhoroshkov 98bd66290e Moved info to the main README file 2023-03-27 01:20:56 +03:00
KirillKhoroshkov 4cdf0b8982 Added java and objective-c codestyles 2023-03-26 01:17:08 +03:00
KirillKhoroshkov 9fe5348a98 Added kotlin codestyle 2023-03-24 13:52:13 +03:00
Roman Pelmegov ba7f792f96 Merge branch 'feature/issue-276' into 'master'
Feature/issue-276

See merge request touchinstinct/BuildScripts!1
2023-03-23 14:56:48 +00:00
Roman Pelmegov 3321f3bdfd Update scripts/export_src.sh 2023-03-08 19:34:19 +00:00
Roman Pelmegov 082f618425 Merge branch 'master' into 'feature/issue-276'
# Conflicts:
#   scripts/export_src.sh
2023-03-08 19:25:19 +00:00
Roman Pelmegov d83a3628e4 Merge branch 'feature/issue-333' into 'master'
Feature/issue-333

See merge request touchinstinct/BuildScripts!2
2023-03-07 16:52:50 +00:00
Roman Pelmegov 0400dbe36d issue-333 break on git clone error 2023-03-07 16:26:54 +00:00
Roman Pelmegov 216c228898 last commit date 2023-03-07 11:07:27 +00:00
Roman Pelmegov 84db8a0e09 issue-333 fix 2023-03-03 15:13:10 +00:00
Roman Pelmegov a58de7d461 issue-276 refactor 2023-03-03 14:53:17 +00:00
Roman Pelmegov c5b7947526 issue-333 use git archive 2023-03-03 14:52:02 +00:00
Roman Pelmegov 4d7182fd67 issue-333 last commit date 2023-03-03 14:33:55 +00:00
rpelmegov 302530f3c2
Update export_src.sh 2023-02-27 05:52:11 +03:00
rpelmegov 4b5ee64737
Update export_src.sh 2023-02-06 14:39:04 +03:00
rpelmegov f0bbbb9929
issue-276 add bad path alarm 2023-01-30 07:14:20 +03:00
Vladimir Makarov ce23c714e5
Merge pull request #332 from TouchInstinct/fix/makefile_identation
Common `Makefile` indentations converted to tabs
2023-01-16 13:28:44 +03:00
Vladimir Makarov 34dcae1d5c Common `Makefile` indentations converted to tabs 2023-01-16 12:22:21 +03:00
rpelmegov 45fbc84578
Update export_src.sh 2023-01-13 06:37:01 +03:00
rpelmegov 55ab60b6ea
Update export_src.sh
<a href="https://github.com/TouchInstinct/BuildScripts/issues/276">issue-276</a> Перед экспортом репозитория проверить файлы на невалидные символы в именах
2022-12-14 14:09:56 +03:00
Ivan Smolin 99281d2105
Merge pull request #330 from TouchInstinct/feature/makefile_shortcuts
add makefile shortcuts for iOS development
2022-12-12 12:11:23 +03:00
Ivan Smolin c4b340ec44 fix Makefile commands 2022-12-09 18:21:07 +03:00
Ivan Smolin a54982e482 add makefile shortcuts for iOS development 2022-12-08 19:00:03 +03:00
Vladimir Makarov 18cf87ea18
Merge pull request #328 from TouchInstinct/fix/default_options
`default_options` empty initializer added for correct method running
2022-10-19 11:37:08 +05:00
Vladimir Makarov 8050647847 `default_options` empty initializer added for correct method running 2022-10-18 19:50:58 +05:00
Vladimir Makarov 1b8d06cb0d
Merge pull request #327 from TouchInstinct/feature/api_key_configuring
API key configuration with environment variable added
2022-10-18 00:13:29 +05:00
Vladimir Makarov 7c22f6e4fc app_store_connect_api_key action calling moved to a separate method, api_key_path used directly 2022-10-17 17:47:18 +05:00
Vladimir Makarov d924c2a995 API key configuration with environment variable added 2022-10-17 12:12:23 +05:00
Anastasiya97 1af248ea15
Merge pull request #322 from TouchInstinct/swagger_api_generator_plugin
Add plugin for Swagger Api Generator
2022-09-16 11:01:30 +03:00
AnastasiyaK97 3dfdb3de1e small fixes 2022-09-14 19:38:43 +03:00
Vladimir Makarov b350383ae7
Merge pull request #324 from TouchInstinct/fix/api_codegen
API Generator codegen fixed
2022-09-06 13:49:45 +05:00
Vladimir Makarov 120551da8f `is_api_spec_under_source_control` method rewritten to return a bool value 2022-09-06 13:39:11 +05:00
Vladimir Makarov 65a5af2e31 API Generator codegen fixed 2022-09-05 23:46:34 +05:00
AnastasiyaK97 f389e6d806 Add plugin for Swagger Api Generator 2022-08-24 18:34:25 +03:00
Vladimir Makarov 8e13458c7f
Merge pull request #320 from TouchInstinct/feature/xmx_update
API Generator `-Xmx` parameter updated to 12Gb
2022-08-19 21:00:43 +05:00
Vladimir Makarov 3f7c655c8e API Generator `-Xmx` parameter updated to 12Gb 2022-08-19 20:51:28 +05:00
Ivan Smolin 732df3171f
Merge pull request #319 from TouchInstinct/feature/api_gen_update
update api_generator to support JDK 16+ and git-less run check
2022-08-08 12:03:07 +03:00
Ivan Smolin e082796930 update api_generator to support JDK 16+ and git-less run check 2022-08-08 11:27:06 +03:00
Александр 44a7fd7f48
Merge pull request #316 from TouchInstinct/multiple_files
Add multiple files generation optional flag
2022-08-02 15:55:14 +03:00
Aleksandr Shushkov 47a67edfff Add emply line 2022-08-02 15:50:52 +03:00
Aleksandr Shushkov 021e4f410e Removed rendundant notice 2022-08-02 15:49:11 +03:00
Aleksandr Shushkov fa8322b142 Change single file flag using 2022-08-02 15:48:09 +03:00
Aleksandr Shushkov 8f4e64bc86 Add multiple files generation optional flag 2022-08-02 10:28:05 +03:00
Ivan Smolin 76ac52accf
Merge pull request #315 from TouchInstinct/feature/support_inheritance_in_xcconfig_options
support inheritance in xcconfig options
2022-07-18 16:29:37 +03:00
Ivan Smolin b908265a3e support inheritance in xcconfig options 2022-07-18 15:30:21 +03:00
Ivan Smolin fe8f581c48
Merge pull request #312 from TouchInstinct/feature/build_logs_in_project_folder
add buildlog_path, speed up pod resolution, update build options helper submodule
2022-06-17 09:52:42 +03:00
Ivan Smolin 2e08a7c062 add buildlog_path, speed up pod resolution, update build options helper submodule 2022-06-17 09:35:06 +03:00
Kirill Nayduik 2753812843
Merge pull request #311 from TouchInstinct/migrate_to_maven_central
Migrate to maven central
2022-05-11 13:59:48 +03:00
Kirill Nayduik c985b62bf0 Revert disabling Android Linter 2022-05-11 13:58:56 +03:00
Kirill Nayduik 5ad312828c Migrate from jCenter to MavenCentral 2022-05-11 13:40:07 +03:00
Kirill Nayduik 68fdb3a815 Disable Android linter as a temporary workaround 2022-04-27 15:27:54 +03:00
Kirill Nayduik 9babae50e5
Merge pull request #308 from TouchInstinct/setupLint_before_evaluate
Setup lint before evaluate
2022-04-26 18:05:16 +03:00
Kirill Nayduik 938d5bd332 Configure setting up linter for projects in different evaluation states 2022-04-25 16:32:34 +03:00
Ivan Smolin 454ec643b3
Merge pull request #307 from TouchInstinct/feature/config_generator_abstract_target_support
add support for custom abstract targets in path to cocoapods xcconfigfiles.
2022-04-20 09:02:11 +03:00
Ivan Smolin 13e28f1b7f add support for custom abstract targets in path to cocoapods xcconfig files. closes #236 2022-04-19 10:33:21 +03:00
Ivan Smolin cd82b034ed
Merge pull request #304 from TouchInstinct/fix/codegen_fixes
fix codegen project name parameter; manage codegen folders for convenience
2022-03-30 14:15:10 +03:00
Ivan Smolin 57dbcee506 fix api-generator default spec folder path 2022-03-29 20:27:37 +03:00
Ivan Smolin 2d98944976 fix codegen project name parameter; manage codegen folders for convenience 2022-03-28 12:04:26 +03:00
Ivan Smolin f30d6ec374
Merge pull request #302 from TouchInstinct/feature/openapi_generator
add support for OpenAPI generation
2022-03-10 18:59:15 +03:00
Ivan Smolin 3220b9a30c fix padding API_NAME parameter to OpenAPI codegen 2022-03-10 18:55:18 +03:00
Ivan Smolin 31d621444c add support for OpenAPI generation 2022-03-10 16:01:57 +03:00
Vladimir Makarov 51f0bd3ee7
Merge pull request #300 from TouchInstinct/feature/firebase_distribution_groups
firebase_app_distribution groups file check added
2022-02-17 22:54:43 +05:00
Vladimir Makarov 6282671df7 firebase_app_distribution groups file check added 2022-02-17 15:59:17 +05:00
Kirill Nayduik f639e34579 Setting up linters for project before evaluate 2022-02-13 20:52:11 +03:00
Александр 2799169e21
Merge pull request #294 from TouchInstinct/feature/export_custom_profile
Add .zprofile exporting
2021-12-20 11:34:11 +03:00
Aleksandr Shushkov 9dad6d730c Add .zprofile exporting 2021-12-19 19:59:17 +03:00
Grigorii 082fc9a719
Merge pull request #291 from TouchInstinct/delete_detekt_UseDataClass
Deleted detekt.UseDataClass rule
2021-12-08 19:02:45 +03:00
Grigorii 3fd44c3bbd Deleted detekt.UseDataClass rule 2021-12-08 17:57:07 +03:00
Александр 6bc60ac0ab
Merge pull request #290 from TouchInstinct/fix/php_not_found
Add user enviroment for localization script
2021-12-07 16:10:29 +03:00
Aleksandr Shushkov 8991f8c2b8 Fix PR issues from @petropavel13 2021-12-07 16:05:29 +03:00
Aleksandr Shushkov d96c126fe2 Fix adding all paths 2021-12-06 21:15:47 +03:00
Aleksandr Shushkov d7acbb0080 Fix variable names 2021-12-06 20:55:16 +03:00
Aleksandr Shushkov 5145245266 Fix executes only export commands 2021-12-06 20:52:59 +03:00
Aleksandr Shushkov 2ec3289b5b Fix PR issues from @petropavel13 2021-12-06 17:37:09 +03:00
Aleksandr Shushkov 22abe5a792 Add failure exit code 2021-12-06 16:19:44 +03:00
Aleksandr Shushkov 1db4cfc771 Fix identation 2021-12-06 16:18:04 +03:00
Aleksandr Shushkov 6b21a9845a Add php installation check 2021-12-06 16:13:46 +03:00
Aleksandr Shushkov 5f009524a3 Add user enviroment for localization script 2021-12-06 16:08:24 +03:00
Александр d2ce219af4
Merge pull request #289 from TouchInstinct/fix/add_custom_enviroment
Add user defined enviroment for copy-paste decetion script
2021-12-01 16:01:38 +03:00
Aleksandr Shushkov c94fb44966 Fix PR issues from @petropavel13 2021-12-01 15:59:42 +03:00
Aleksandr Shushkov 0fc2eb03c6 Add user defined enviroment for copy-paste decetion script 2021-12-01 15:45:13 +03:00
Ivan Smolin 81499749a1
Merge pull request #230 from TouchInstinct/feature/unused
Add unused resources script
2021-11-03 18:30:43 +03:00
Timur Kayumov 0df12c3b26
Merge pull request #285 from TouchInstinct/fix/Linter_paths_generation
Fix file paths when collect changes for linting
2021-11-03 13:15:16 +02:00
Timur Kayumov c2259b12b2 Revert path argument 2021-11-03 13:13:00 +02:00
Timur Kayumov e1290036ff Fix file paths when collect changes for linting 2021-11-03 12:57:37 +02:00
svshkv b9b7dfe3f7
Merge pull request #282 from TouchInstinct/feature/fastlane_xcode_version
Added setting xcode version
2021-10-27 12:47:52 +03:00
Alexander Rutsman e1e15d619e Added search for the newest version on ruby 2021-10-27 11:20:34 +03:00
Alexander Rutsman 7061bad2ec Added search for the newest version 2021-10-20 16:01:13 +03:00
Alexander Rutsman b319b97522 Added default xcode version 2021-10-12 19:09:36 +03:00
Alexander Rutsman ecc34d227a Added default xcode version 2021-10-12 18:42:00 +03:00
Alexander Rutsman e975ff0ed0 Added setting xcode version 2021-10-12 15:49:26 +03:00
Loupehope befc933117
Merge pull request #281 from TouchInstinct/feat/remove-lazy_var
feat: remove lazy_var
2021-09-23 19:36:56 +03:00
Vlad Suhomlinov b9429f8aaf feat: remove lazy_var 2021-09-23 19:31:39 +03:00
Loupehope ee5299c318
Merge pull request #279 from TouchInstinct/tech/lint_only_changed_files
feat: lint only changed files
2021-09-16 10:34:52 +03:00
Vlad Suhomlinov 1678af0116 docs: remove useless docs 2021-09-15 19:29:21 +03:00
Vlad Suhomlinov f98c1af719 refactor: correct lint_files_path creation 2021-09-14 08:51:53 +03:00
Vlad Suhomlinov a455072e14 refactor: revert xcargs 2021-09-13 19:26:01 +03:00
Vlad Suhomlinov 44d4ff9f74 refactor: correct fastfile 2021-09-13 19:19:37 +03:00
Vlad Suhomlinov 494bc4886b refactor: add FORCE_LINT to fastlane 2021-09-13 19:10:35 +03:00
Vlad Suhomlinov db99ec0009 refactor: add gitignore 2021-09-13 18:47:44 +03:00
Vlad Suhomlinov 9e8d088017 refactor: add FORCE_LINT arg 2021-09-13 18:47:37 +03:00
Vlad Suhomlinov 5a6dd866f7 refactor: typo 2021-09-13 11:32:21 +03:00
Vlad Suhomlinov 088114cb5c refactor: enable --use-alternative-excluding 2021-09-12 11:49:37 +03:00
Vlad Suhomlinov 40f6d12e15 refactor: enable --force-exclude 2021-09-11 13:21:48 +03:00
Vlad Suhomlinov e725685a9e refactor: add allow_zero_lintable_files to swiftlint 2021-09-11 13:01:10 +03:00
Vlad Suhomlinov 8094a04ab3 feat: lint only changed files 2021-09-11 12:48:55 +03:00
Ivan Smolin 1e95815cce
Merge pull request #277 from TouchInstinct/feature/export_project_documentation
GIT_BRANCH environment variable handling + add some docs
2021-08-31 12:21:18 +03:00
Ivan Smolin 54fdb267bc GIT_BRANCH environment variable handling + add some docs 2021-08-30 15:34:50 +03:00
Dmitriy 501ff89f28
Merge pull request #272 from TouchInstinct/feature/lazy_var_lint
Update .swiftlint.yml
2021-08-12 11:02:05 +03:00
Dmitriy 51e9a3b190
Update .swiftlint.yml 2021-08-09 12:11:51 +03:00
Dmitriy 9ae6e92e66
Update .swiftlint.yml
pr fix
2021-08-09 12:10:27 +03:00
Ivan Smolin f5b21784fe
Merge pull request #273 from TouchInstinct/feature/install_env_script
add install_env script for build phases
2021-08-09 12:05:38 +03:00
Ivan Smolin 1545208c46 add install_env script for build phases 2021-08-09 11:58:54 +03:00
Dmitriy 5ac9fd8232
Update .swiftlint.yml
add lazy var rule to swiftlint
2021-08-09 11:55:43 +03:00
Ivan Smolin cbf10f95f9
Merge pull request #269 from TouchInstinct/feature/localization_script_improvements
localization script refactoring
2021-08-04 11:03:51 +03:00
Ivan Smolin c2104468bd remove debug output 2021-08-04 11:00:50 +03:00
Ivan Smolin 7c4149778c add backslashes before characters that need to be escaped 2021-08-04 10:45:04 +03:00
Ivan Smolin 6cdd30a872 fix workspace path for code generation 2021-07-28 22:02:43 +03:00
Ivan Smolin 8d0449714b set xcconfig for framework targets as well 2021-07-28 15:58:18 +03:00
Ivan Smolin 6a032c324f replace existing options when generating xcconfigs 2021-07-27 15:03:21 +03:00
Ivan Smolin 63ecad8042 remove hadcoded CODE_SIGN_STYLE key; remove PROVISIONING_PROFILE_SPECIFIER auto generation 2021-07-22 09:29:22 +03:00
Ivan Smolin 0d555bea19 generate xcodeproj before increment build number 2021-07-21 21:06:58 +03:00
Ivan Smolin 82a44c2a1c disable cyrillic_strings rule for String+Localization.swift 2021-07-21 17:56:06 +03:00
Ivan Smolin cf2aa3f7ee localization script refactoring 2021-07-21 17:18:13 +03:00
Ivan Smolin 73abd1564f
Merge pull request #268 from TouchInstinct/feature/xcodegen_support
add xcodegen support
2021-07-21 14:00:43 +03:00
Ivan Smolin ad2172cd27 add xcodegen support 2021-07-21 13:41:14 +03:00
svshkv c302278751
Merge pull request #266 from TouchInstinct/feature/firebase_separation
Feature/firebase separation
2021-07-16 12:24:58 +03:00
Alexander Rutsman 3c5135ea5e Git revert HEAD 2021-07-07 15:23:29 +03:00
Alexander Rutsman efb5c8b60e Edit timeout 2021-07-06 12:56:18 +03:00
Alexander Rutsman 3f70495e4b Removed google service prefix 2021-07-05 16:29:00 +03:00
Ivan Smolin 1b86887958
Merge pull request #265 from TouchInstinct/fix/fastlane_2.187
replace timeout: false with timeout: 0
2021-07-04 17:03:55 +03:00
Ivan Smolin e0913de8a3 replace timeout: false with timeout: 0 according to https://github.com/fastlane/fastlane/pull/18894 2021-07-04 16:57:00 +03:00
Loupehope 79105bf5f9
Merge pull request #261 from TouchInstinct/feature/move_to_workspace
Feature - move to workspace
2021-05-21 12:48:00 +03:00
Vlad Suhomlinov 045b57e72d refactor: complete app name 2021-05-13 17:56:37 +03:00
Vlad Suhomlinov fa9ccef66b refactor: correct typo 2021-05-13 17:47:15 +03:00
Vlad Suhomlinov a132bcd939 refactor: update path to xcworkspace 2021-05-13 17:41:44 +03:00
Vlad Suhomlinov 908f69b1f8 feat: run code generation for workspace 2021-05-13 17:27:51 +03:00
Loupehope 566bbe1801
Merge pull request #260 from TouchInstinct/fix/api_generator_url
fix: api generator url
2021-05-11 18:48:34 +03:00
Loupehope 515e6ac5be
fix: api generator url 2021-05-11 18:45:54 +03:00
Ivan Smolin 82154894c1
Merge pull request #259 from TouchInstinct/feature/update_api_generator_download_url
update api generator download url
2021-05-11 18:06:06 +03:00
Ivan Smolin 8813dacd6f update api generator download url 2021-05-11 18:04:46 +03:00
rybakovi 27f69a2dcf
Merge pull request #258 from TouchInstinct/fix/api-gen
upd version and location
2021-04-29 20:45:11 +03:00
rybakovi a83d6074b2 upd version and location 2021-04-29 20:42:14 +03:00
Loupehope 257c8e966b
Merge pull request #257 from TouchInstinct/fix/remove_useless_path
Remove useless path to pmd
2021-04-29 11:30:57 +03:00
Loupehope daf50493e6
Remove useless path to pmd 2021-04-29 08:03:46 +03:00
Ivan Smolin 2ac36fbc1b
Merge pull request #256 from TouchInstinct/feature/create_intermediate_directories_in_local_storage
create intermediate directories in LocalStorage.upload_files
2021-04-19 14:19:49 +03:00
Ivan Smolin 784f619166 create intermediate directories in LocalStorage.upload_files 2021-04-19 13:57:53 +03:00
Ivan Smolin cd606ce17d
Merge pull request #242 from TouchInstinct/feature/build_phases_script_improvements
Feature/build phases script improvements
2021-03-26 10:54:15 +03:00
Loupehope 4f9aa52800
Merge pull request #254 from TouchInstinct/feature/add_code_generation_phase
Add code generation phase to ci
2021-03-23 18:09:59 +03:00
Vlad bfad757f23 Remove empty spaces 2021-03-23 17:54:53 +03:00
Vlad 8529a6f41f Remove comments 2021-03-23 17:37:51 +03:00
Vlad ddf7e0228b Correct code generation input 2021-03-23 17:07:09 +03:00
Vlad 43485eb8f5 Correct params input to sh 2021-03-23 16:56:39 +03:00
Vlad f5d3b7e4ea Add xcodeproj_path to code generation 2021-03-23 16:49:22 +03:00
Vlad fc1c0ac74b Add cpde generation phase 2021-03-23 16:29:00 +03:00
Loupehope 40db24db3c
Merge pull request #251 from TouchInstinct/feature/add_resources_to_exclude
Add resources to exclude
2021-03-12 20:03:29 +03:00
Vlad e5c4db8c10 Add resources to exclude 2021-03-12 19:41:16 +03:00
Loupehope 621e46757d
Merge pull request #249 from TouchInstinct/fix/path_to_executable_pmd
Path to executable pmd
2021-03-09 13:22:43 +03:00
Vlad 2c0e89dbf5 Add path to pmd 2021-03-09 13:14:49 +03:00
Loupehope 4a72255a79
Merge pull request #246 from TouchInstinct/feature/pattern_matching_rule
Feature - pattern matching rule
2021-02-11 18:41:48 +03:00
Vlad f62bc00b9c Remove fallthrough 2021-02-11 18:33:05 +03:00
Ivan Smolin 88e8dbf2b7
Merge pull request #244 from TouchInstinct/feature/api_key_fixes
use two api keys: project and touchin
2021-02-11 18:27:53 +03:00
Ivan Smolin f0e0cb7e02 add fallthrough rule, use warnings instead of errors for most kind of custom rules 2021-02-11 18:22:14 +03:00
Vlad 69ec87dc47 Update pattern_matching 2021-02-11 18:19:50 +03:00
Vlad 2c97109908 Add pattern_matching and fallthrough rules 2021-02-11 17:45:45 +03:00
Ivan Smolin fec78fd0bc use two api keys: project and touchin 2021-02-04 19:49:45 +03:00
Ivan Smolin d0256372c1 add check for simultaneous usage of Input Files and Input File Lists 2021-01-21 17:28:52 +03:00
Ivan Smolin 0546268696 add support for xcfilelist list in read_input_file_names 2021-01-21 15:27:44 +03:00
Ivan Smolin 7c9680f4c9 Merge branch 'master' into feature/build_phases_script_improvements 2021-01-20 12:31:28 +03:00
Ivan Smolin 54fd9f1106
Merge pull request #243 from TouchInstinct/feature/fastlane_app_store_connect_api
use App Store Connect API for match and upload_to_app_store
2021-01-20 11:17:06 +03:00
Ivan Smolin 039ddac90a use App Store Connect API for match and upload_to_app_store 2021-01-19 18:09:27 +03:00
Ivan Smolin 8794713900 add smart skipping for api_generator script 2021-01-18 18:19:41 +03:00
Ivan Smolin ca37784c57 add doc to swiftlint about input files 2021-01-18 16:36:18 +03:00
Ivan Smolin 7819b0e4cd add doc about SRCROOT 2021-01-18 16:18:00 +03:00
Ivan Smolin a682c25dd5 misunstaged runner.sh 2021-01-18 15:57:16 +03:00
Ivan Smolin b27fa554fb delete runner.sh, update swiftlint script 2021-01-18 15:55:40 +03:00
Ivan Smolin bd2138f58d update swiftlint config 2021-01-18 15:55:07 +03:00
Ivan Smolin e2f85337c0 remove REFACTORING_MODE 2021-01-18 15:54:54 +03:00
Ivan Smolin bb432d4220 add doc about SCRIPT_DIR variable 2021-01-15 18:58:45 +03:00
Ivan Smolin be7e522f38 copy_paste_detection refactoring 2021-01-15 18:51:53 +03:00
Ivan Smolin e0300fcd07 remove carthage & rome 2021-01-15 18:51:15 +03:00
Ivan Smolin 093f16a578 remove yarn install, use new firebase plugin API 2021-01-15 11:35:26 +03:00
Ivan Smolin 2c5f978eeb final changes 2021-01-14 18:37:53 +03:00
Ivan Smolin 9c247bbf4a improve copy-paste detection script 2021-01-14 18:00:09 +03:00
Ivan Smolin 454ae16cbe remove GOOGLE_SERVICE_INFO_PLIST_PATH generation from xcconfig files 2021-01-13 18:21:54 +03:00
Loupehope 659baf6ced
Merge pull request #241 from TouchInstinct/feature/guard_self_linter
Add strong self rule
2020-12-30 14:49:09 +03:00
Vlad db8cd599b3 Add strong self rule 2020-12-30 14:20:10 +03:00
Loupehope 687197d06d
Merge pull request #240 from TouchInstinct/feature/make_feature_toggles_simplier
Update feature toggles work
2020-12-29 14:50:00 +03:00
Vlad f684dbc029 Fix PR 2020-12-29 14:43:47 +03:00
Vlad 175a97fc5f Code correction 2020-12-28 08:30:36 +03:00
Vlad a042e43450 Fix script logic 2020-12-27 23:23:36 +03:00
Vlad 2af414680f Fix paths 2020-12-27 22:32:45 +03:00
Vlad 417ddaafba Update naming 2020-12-27 22:22:52 +03:00
Vlad 9df5643e76 Merge branch 'master' into feature/make_feature_toggles_simplier 2020-12-27 22:13:56 +03:00
Vlad 07b0df8a46 Code correction 2020-12-27 22:09:28 +03:00
Vlad bd19a47a75 Update feature toggles work
Add templates
Add template manager
Updaet features generation scripts
2020-12-27 22:07:20 +03:00
Ivan Smolin b77b2288f2
Merge pull request #239 from TouchInstinct/fix/generated_exclude
add Generated, as well as **/Generated (for multiple swiftlint)
2020-12-21 14:24:33 +03:00
Ivan Smolin ec27c3bc81 add Generated, as well as **/Generated (for multiple swiftlint) 2020-12-21 14:22:52 +03:00
Loupehope 7a91383726
Merge pull request #237 from TouchInstinct/feature/feature_toggles
Add generateFeaturesFile lane and feature generator
2020-12-18 18:36:11 +03:00
Vlad 688a828548 Fix PR 2020-12-18 18:30:19 +03:00
Vlad 7b5ba18dfa Fix PR 2020-12-18 18:29:28 +03:00
Vlad 1a344aeed7 Fix PR 2020-12-18 18:03:04 +03:00
Vlad 4777c0c597 Fix PR 2020-12-18 17:55:27 +03:00
Vlad 545f8d4c2f Fix PR 2020-12-15 18:27:25 +03:00
Vlad 52c61b3f2e Merge branch 'feature/feature_toggles' of github.com:TouchInstinct/BuildScripts into feature/feature_toggles 2020-12-15 15:55:32 +03:00
Vlad 64c8f85298 Fix PR 2020-12-15 15:53:37 +03:00
Vlad 31cc96b6c6 Fix enum path 2020-12-15 11:52:09 +03:00
Vlad d7a571400d Code correction 2020-12-15 11:40:16 +03:00
Vlad 149a4d2dcb Code correction 2020-12-15 11:23:15 +03:00
Vlad 4564ffbd99 Add comment 2020-12-15 11:06:23 +03:00
Vlad e7574decbc Add check for nil 2020-12-15 11:05:35 +03:00
Vlad 1f321c27c9 Add manager module and code correction 2020-12-15 10:59:14 +03:00
Vlad b3751302a9 Add features generator 2020-12-14 20:58:19 +03:00
Ivan Smolin 95e915c003
Merge pull request #238 from TouchInstinct/fix/redundant_boolean_condition
disable comments evaluation for redundant_boolean_condition rule
2020-12-14 13:47:43 +03:00
Vlad a5f2b49a51 Fix names filter 2020-12-14 11:58:58 +03:00
Ivan Smolin 4cf2810533 disable comments evaluation for redundant_boolean_condition rule 2020-12-13 02:01:04 +03:00
Vlad 2712da9b89 Code correction 2020-12-12 21:16:07 +03:00
Vlad 136beef976 Fix typo 2020-12-12 21:12:58 +03:00
Vlad 46be166a04 Code correction 2020-12-12 21:12:05 +03:00
Vlad 67418eefc3 Code correction 2020-12-12 20:57:09 +03:00
Vlad a47f0b6218 Fix file type 2020-12-12 20:00:22 +03:00
Vlad aa00fe13ca Add Features class 2020-12-12 19:55:10 +03:00
Vlad dbfc6153ab Add uploadFeaturesToProject lane 2020-12-12 18:17:39 +03:00
Ivan Smolin ea38c36478
Merge pull request #235 from TouchInstinct/feature/improve_cpd_and_unused_scripts
make all build script calls relative
2020-11-24 10:43:34 +03:00
Ivan Smolin 4dbdcfce7a make all build script calls relative 2020-11-23 19:04:57 +03:00
Ivan Smolin 5669222c5c
Merge pull request #234 from TouchInstinct/feature/multiple_swiftlint_fixes
some fixes and improvements for multiple swiftlint
2020-11-23 19:03:42 +03:00
Ivan Smolin 1054ae4d3e add prefer_zero_over_explicit_init rule 2020-11-23 17:53:13 +03:00
Ivan Smolin 44d4e4175d fix undefined method mktmpdir 2020-11-23 17:41:18 +03:00
Ivan Smolin cb21c0ab03 some fixes and improvements for multiple swiftlint 2020-11-23 17:28:55 +03:00
Ivan Smolin 50499df38e
Merge pull request #232 from TouchInstinct/feature/support_custom_lane_name_and_scheme
add support for custom scheme and lane name via options
2020-10-20 14:53:12 +03:00
Ivan Smolin 784063b996 add support for custom scheme and lane name via options 2020-10-20 13:36:48 +03:00
Ivan Smolin 6c32607ef8
Merge pull request #231 from TouchInstinct/feature/match_local_storage
match local storage
2020-10-15 12:26:49 +03:00
Ivan Smolin fe5564da7b update ManuallyUpdateCodeSigning lane so it can use local storage 2020-10-13 21:54:31 +03:00
Ivan Smolin d0f6f7d6a8 add local storage (project folder) type for match 2020-10-13 17:41:04 +03:00
Vlad e9dcba923c Update exe 2020-10-02 12:40:17 +03:00
Vlad bbe5e3a908 Code correction 2020-10-02 11:40:39 +03:00
Vlad ef6d0eb3cc Code correction 2020-10-02 11:28:06 +03:00
Vlad aa152a8fd4 Code correction 2020-10-02 11:21:45 +03:00
Vlad c11f3d4204 Update exe 2020-10-02 11:14:35 +03:00
Vlad 9a4abfd68b Code correction 2020-10-02 10:59:23 +03:00
Vlad d99cf7cb03 Code correction 2020-10-02 10:55:51 +03:00
Vlad ef8a3b6cf5 Add unused resources script 2020-10-02 10:30:35 +03:00
55 changed files with 2223 additions and 884 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# macOS
.DS_Store

View File

@ -1 +1,26 @@
# BuildScripts # BuildScripts
## Настройки форматирования
Позволяют настроить одинаковое форматирования кода в Android Studio у всех, кто работает на проекте.
Настройки соответствуют
[Правилам оформления Kotlin кода](https://styleguide.docs.touchin.ru/Coding/KotlinCodestyle.html)
Есть два варианта использования: подключить к проекту или импортировать схему в Android Studio.
### Как подключить к проекту:
1. Скопировать директорию [`codeStyles`](./codeStyles) в директорию проекта `.idea`
2. Добавить в файл `.gitignore` строку `!.idea/codeStyles`
3. Перезапустить Android Studio, чтобы настройки применились
При таком варианте настройки будут применены у всех, кто работает на проекте.
И только для одного конкретного проекта.
### Как импортировать схему в Android Studio:
1. Скачать схему [`codeStyles/Project.xml`](./codeStyles/Project.xml)
2. В Android Studio перейти в `File` > `Settings` > `Editor` > `Code Style`
3. Нажать на шестеренку справа от выпадающего списка схем и выбрать `Import Scheme`
4. В открывшемся окне указать путь до сохраненной схемы и нажать `ОК`
5. В открывшемся окне ввести название новой схемы и нажать `ОК`

View File

@ -1,8 +0,0 @@
<application>
<component name="CodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value />
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="TouchInstinct" />
</component>
</application>

View File

@ -1,5 +0,0 @@
<application>
<component name="CodeStyleSchemeSettings">
<option name="CURRENT_SCHEME_NAME" value="TouchInstinct" />
</component>
</application>

249
codeStyles/Project.xml Normal file
View File

@ -0,0 +1,249 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="120" />
<option name="SOFT_MARGINS" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="LAYOUT_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
<option name="MANIFEST_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
<option name="OTHER_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="GENERATE_FINAL_LOCALS" value="true" />
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
<option name="ALIGN_MULTILINE_ANNOTATION_PARAMETERS" value="true" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" static="false" withSubpackages="true" />
<emptyLine />
<package name="com" static="false" withSubpackages="true" />
<emptyLine />
<package name="junit" static="false" withSubpackages="true" />
<emptyLine />
<package name="net" static="false" withSubpackages="true" />
<emptyLine />
<package name="org" static="false" withSubpackages="true" />
<emptyLine />
<package name="java" static="false" withSubpackages="true" />
<emptyLine />
<package name="javax" static="false" withSubpackages="true" />
<emptyLine />
<package name="" static="false" withSubpackages="true" />
<emptyLine />
<package name="" static="true" withSubpackages="true" />
<emptyLine />
</value>
</option>
<option name="JD_P_AT_EMPTY_LINES" value="false" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value />
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="true" />
<option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="true" />
<option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="true" />
<option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="true" />
<option name="CONTINUATION_INDENT_IN_ELVIS" value="true" />
<option name="ALLOW_TRAILING_COMMA" value="true" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair header="h" source="cpp" />
<pair header="h" source="c" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_KEEP_BLANK_LINES" value="1" />
</XML>
<codeStyleSettings language="JAVA">
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="RESOURCE_LIST_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="WRAP_LONG_LINES" value="true" />
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
<option name="ENUM_CONSTANTS_WRAP" value="5" />
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="ENUM_CONSTANTS_WRAP" value="5" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -1,254 +0,0 @@
<code_scheme name="TouchInstinct">
<option name="GENERATE_FINAL_LOCALS" value="true" />
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="150" />
<option name="JD_P_AT_EMPTY_LINES" value="false" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
<option name="ALIGN_MULTILINE_ANNOTATION_PARAMETERS" value="true" />
</JavaCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="150" />
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="RESOURCE_LIST_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="WRAP_LONG_LINES" value="true" />
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
<option name="ENUM_CONSTANTS_WRAP" value="2" />
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>

View File

@ -7,7 +7,7 @@ plugins {
// The kotlin-dsl plugin requires a repository to be declared // The kotlin-dsl plugin requires a repository to be declared
repositories { repositories {
jcenter() mavenCentral()
google() google()
} }
@ -36,6 +36,10 @@ gradlePlugin {
id = "api-generator-android" id = "api-generator-android"
implementationClass = "apigen.ApiGeneratorAndroidPlugin" implementationClass = "apigen.ApiGeneratorAndroidPlugin"
} }
create("swagger-generator-android") {
id = "swagger-generator-android"
implementationClass = "apigen.SwaggerApiGeneratorAndroidPlugin"
}
create("api-generator-backend") { create("api-generator-backend") {
id = "api-generator-backend" id = "api-generator-backend"
implementationClass = "apigen.ApiGeneratorBackendPlugin" implementationClass = "apigen.ApiGeneratorBackendPlugin"

View File

@ -12,14 +12,14 @@ abstract class ApiGeneratorPlugin : Plugin<Project> {
companion object { companion object {
const val API_GENERATOR_CONFIG = "apiGenerator" const val API_GENERATOR_CONFIG = "apiGenerator"
const val API_GENERATOR_EXT_NAME = "apiGenerator" const val API_GENERATOR_EXT_NAME = "apiGenerator"
const val API_GENERATOR_DEFAULT_VERSION = "1.4.0-beta5" const val API_GENERATOR_DEFAULT_VERSION = "1.4.0-beta10"
} }
override fun apply(target: Project) { override fun apply(target: Project) {
with(target) { with(target) {
repositories { repositories {
maven { maven {
url = uri("https://dl.bintray.com/touchin/touchin-tools") url = uri("https://maven.dev.touchin.ru")
metadataSources { metadataSources {
artifact() artifact()
} }

View File

@ -0,0 +1,91 @@
package apigen
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.repositories
class SwaggerApiGeneratorAndroidPlugin : Plugin<Project> {
private companion object {
const val GENERATOR_CONFIG = "swaggerCodegen"
const val GENERATOR_VERSION = "3.0.34"
const val TI_GENERATOR_CONFIG = "TIKotlin-swagger-codegen"
const val TI_GENERATOR_VERSION = "1.0.0"
const val GENERATOR_EXT_NAME = "swaggerApiGenerator"
const val MAVEN_URL = "https://maven.dev.touchin.ru"
}
override fun apply(target: Project) {
with(target) {
repositories {
maven {
url = uri(MAVEN_URL)
metadataSources {
artifact()
}
}
}
configurations.create(GENERATOR_CONFIG)
configurations.create(TI_GENERATOR_CONFIG)
dependencies {
add(TI_GENERATOR_CONFIG, "ru.touchin:TIKotlin-swagger-codegen:$TI_GENERATOR_VERSION")
add(GENERATOR_CONFIG, "io.swagger.codegen.v3:swagger-codegen-cli:$GENERATOR_VERSION")
}
extensions.create<SwaggerApiGeneratorExtension>(GENERATOR_EXT_NAME)
val apiGenTask = createSwaggerApiGeneratorTask()
gradle.projectsEvaluated {
tasks.getByName("preBuild").dependsOn(apiGenTask)
}
}
}
protected fun Project.getExtension(): SwaggerApiGeneratorExtension = extensions.getByName(GENERATOR_EXT_NAME) as SwaggerApiGeneratorExtension
private fun Project.createSwaggerApiGeneratorTask(): Task = tasks.create(GENERATOR_CONFIG).doLast {
val extension = getExtension()
val taskWorkingDir = extension.taskWorkingDir ?: throw IllegalStateException("Configure taskWorkingDir for swagger generator plugin")
val apiSchemesFilePath = extension.apiSchemesFilePath ?: throw IllegalStateException("Configure sourceFilePath for swagger generator plugin")
val outputDir = extension.outputDir ?: throw IllegalStateException("Configure outputDir for swagger generator plugin")
val projectName = extension.projectName ?: throw IllegalStateException("Configure projectName for swagger generator plugin")
javaexec {
workingDir = file(taskWorkingDir)
classpath = files(configurations.getByName(GENERATOR_CONFIG).asPath,
configurations.getByName(TI_GENERATOR_CONFIG).asPath)
main = "io.swagger.codegen.v3.cli.SwaggerCodegen"
args = listOfNotNull(
"generate",
"-i",
apiSchemesFilePath,
"-l",
"TIKotlinCodegen",
"-o",
outputDir,
"--additional-properties",
"projectName=$projectName"
)
}
}
}
open class SwaggerApiGeneratorExtension(
var taskWorkingDir: String? = null,
var apiSchemesFilePath: String? = null,
var outputDir: String? = null,
var projectName: String? = null
)
fun Project.swaggerApiGenerator(configure: Action<SwaggerApiGeneratorExtension>): Unit =
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("swaggerApiGenerator", configure)

View File

@ -33,8 +33,8 @@ class AndroidLinter : Linter {
.flatten() .flatten()
override fun setupForProject(project: Project, extension: StaticAnalysisExtension) { override fun setupForProject(project: Project, extension: StaticAnalysisExtension) {
project.gradle.projectsEvaluated { project.beforeEvaluate {
project.subprojects subprojects
.mapNotNull { it.extensions.findByType<AppExtension>() } .mapNotNull { it.extensions.findByType<AppExtension>() }
.first() .first()
.lintOptions.apply { .lintOptions.apply {
@ -45,8 +45,8 @@ class AndroidLinter : Linter {
htmlReport = false htmlReport = false
isCheckDependencies = true isCheckDependencies = true
disable("MissingConstraints", "VectorRaster") disable("MissingConstraints", "VectorRaster")
xmlOutput = project.getLintReportFile() xmlOutput = getLintReportFile()
lintConfig = project.file("${extension.buildScriptDir}/static_analysis_configs/lint.xml") lintConfig = file("${extension.buildScriptDir}/static_analysis_configs/lint.xml")
} }
} }
} }

View File

@ -34,15 +34,18 @@ class CpdLinter : Linter {
} }
override fun setupForProject(project: Project, extension: StaticAnalysisExtension) { override fun setupForProject(project: Project, extension: StaticAnalysisExtension) {
project.extensions.findByType<CpdExtension>()!!.apply { project.afterEvaluate {
isSkipLexicalErrors = true extensions.findByType<CpdExtension>()!!.apply {
language = "kotlin" isSkipLexicalErrors = true
minimumTokenCount = 60 language = "kotlin"
} minimumTokenCount = 60
project.tasks.withType<Cpd> { }
reports.xml.destination = project.getCpdReportFile() tasks.withType<Cpd> {
ignoreFailures = true reports.xml.required.set(true)
source = project.getSources(extension.excludes) reports.xml.destination = getCpdReportFile()
ignoreFailures = true
source = getSources(extension.excludes)
}
} }
} }

View File

@ -32,27 +32,27 @@ class DetektLinter : Linter {
.flatten() .flatten()
override fun setupForProject(project: Project, extension: StaticAnalysisExtension) { override fun setupForProject(project: Project, extension: StaticAnalysisExtension) {
project project.afterEvaluate {
.tasks tasks.withType(Detekt::class.java) {
.withType(Detekt::class.java) { exclude("**/test/**")
exclude("**/test/**") exclude("resources/")
exclude("resources/") exclude("build/")
exclude("build/") exclude("tmp/")
exclude("tmp/") jvmTarget = "1.8"
jvmTarget = "1.8"
config.setFrom(project.files("${extension.buildScriptDir!!}/static_analysis_configs/detekt-config.yml")) config.setFrom(files("${extension.buildScriptDir!!}/static_analysis_configs/detekt-config.yml"))
reports { reports {
txt.enabled = false txt.enabled = false
html.enabled = false html.enabled = false
xml { xml {
enabled = true enabled = true
destination = project.getDetektReportFile() destination = getDetektReportFile()
}
} }
source = project.getSources(extension.excludes)
} }
source = getSources(extension.excludes)
}
}
} }
override fun getTaskNames(project: Project, buildType: String?): List<String> = listOf(":detekt") override fun getTaskNames(project: Project, buildType: String?): List<String> = listOf(":detekt")

View File

@ -28,8 +28,6 @@ class StaticAnalysisAndroidPlugin : StaticAnalysisPlugin() {
) )
} }
} }
} }
} }
} }

View File

@ -26,9 +26,7 @@ abstract class StaticAnalysisPlugin : Plugin<Project> {
val linters = createLinters() val linters = createLinters()
afterEvaluate { linters.forEach { it.setupForProject(target, extensions.getByType()) }
linters.forEach { it.setupForProject(target, extensions.getByType()) }
}
gradle.projectsEvaluated { gradle.projectsEvaluated {
createStaticAnalysisTasks(target, linters) createStaticAnalysisTasks(target, linters)

View File

@ -1,31 +1,71 @@
#!/bin/sh #!/bin/sh
# Description:
# Creates archive with source code of multiple repositories.
#
# Parameters:
# $1 - github repository name without suffix (project name).
# $2, $3, ..., $n - repository suffixes (platforms).
#
# Optional environment variables:
# GIT_BRANCH - branch to use. Default - master.
#
# Example of usage:
# export_src.sh TestProject ios android backend
# GIT_BRANCH="develop" ./export_src.sh TestProject ios web
#
if [ -z "${GIT_BRANCH}" ]; then
GIT_BRANCH="master"
fi
LAST_COMMIT_DATE=""
PROJECT_NAME=$1 PROJECT_NAME=$1
SRC_FOLDER_NAME=${PROJECT_NAME}-src-$(date +%F) SRC_FOLDER_NAME="${PROJECT_NAME}-src"
SRC_DIR=./${SRC_FOLDER_NAME} SRC_DIR="./${SRC_FOLDER_NAME}"
COMMAND_LINE_ARGUMENTS=$@ COMMAND_LINE_ARGUMENTS=$@
clone_platform() { clone_platform() {
PROJECT_DIR=$1 PROJECT_NAME=$1
PLATFORM=$2 PLATFORM=$2
git clone --recurse-submodules -j8 git@github.com:TouchInstinct/${PROJECT_DIR}-${PLATFORM}.git --branch master if git clone --recurse-submodules -j8 "ssh://git@git.ti:7999/touchinstinct/${PROJECT_NAME}-${PLATFORM}.git" --branch "${GIT_BRANCH}"; then
cd ${PROJECT_NAME}-${PLATFORM}
COMMIT_DATE=`git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d'`
if [[ $LAST_COMMIT_DATE < $COMMIT_DATE ]]; then
LAST_COMMIT_DATE="${COMMIT_DATE}"
fi
cd ..
else
exit 1
fi
} }
mkdir -p ${SRC_DIR} mkdir -p "${SRC_DIR}"
cd ${SRC_DIR} cd "${SRC_DIR}"
for argument in ${COMMAND_LINE_ARGUMENTS} for argument in ${COMMAND_LINE_ARGUMENTS}
do do
if [ $argument != $PROJECT_NAME ] if [ $argument != $PROJECT_NAME ]; then
then
platform=${argument} # all arguments after project name treated as platforms platform=${argument} # all arguments after project name treated as platforms
clone_platform ${PROJECT_NAME} ${platform} clone_platform ${PROJECT_NAME} ${platform}
fi fi
done done
ERR_PATHS=$(find . -name "*[<>:\\|?*]*" | xargs -I %s echo "- %s")
if [ "$ERR_PATHS" ]; then
echo "Export aborted! Invalid characters found in file or directories name(s):\n$ERR_PATHS"
exit 1
fi
if [ -z "${EXPORT_DATE}" ]; then
EXPORT_DATE="${LAST_COMMIT_DATE}"
fi
find . -name ".git*" -print0 | xargs -0 rm -rf find . -name ".git*" -print0 | xargs -0 rm -rf
zip -r ${SRC_FOLDER_NAME}.zip . zip -r -q "${SRC_FOLDER_NAME}-${EXPORT_DATE}".zip .
open . open .

View File

@ -387,9 +387,6 @@ style:
UnusedPrivateMember: UnusedPrivateMember:
active: true active: true
allowedNames: "(_|ignored|expected|serialVersionUID)" allowedNames: "(_|ignored|expected|serialVersionUID)"
UseDataClass:
active: true
excludeAnnotatedClasses: ""
UtilityClassWithPublicConstructor: UtilityClassWithPublicConstructor:
active: false active: false
VarCouldBeVal: VarCouldBeVal:

View File

@ -15,7 +15,6 @@ opt_in_rules:
# idiomatic # idiomatic
- legacy_random
- legacy_multiple - legacy_multiple
- pattern_matching_keywords - pattern_matching_keywords
- redundant_nil_coalescing - redundant_nil_coalescing
@ -32,6 +31,12 @@ opt_in_rules:
- fatal_error_message - fatal_error_message
- extension_access_modifier - extension_access_modifier
- explicit_init - explicit_init
- fallthrough
- unavailable_function
- prefer_zero_over_explicit_init
- discouraged_assert
- discouraged_none_name
- shorthand_optional_binding
# style # style
@ -53,27 +58,46 @@ opt_in_rules:
- closure_spacing - closure_spacing
- closure_end_indentation - closure_end_indentation
- prefer_self_type_over_type_of_self - prefer_self_type_over_type_of_self
- closure_parameter_position
- comma_inheritance
- self_binding
- prefer_self_in_static_references
- direct_return
- period_spacing
# lint # lint
- private_action - private_action
- private_outlet - private_outlet
- prohibited_super_call - prohibited_super_call
- unused_import
- unused_declaration
- identical_operands - identical_operands
- overridden_super_call - overridden_super_call
- unowned_variable_capture - unowned_variable_capture
- strong_iboutlet
- lower_acl_than_parent
- comment_spacing
- ibinspectable_in_extension
- private_subject
- unhandled_throwing_task
# metrics # metrics
- enum_case_associated_values_count - enum_case_associated_values_count
analyzer_rules:
- capture_variable
- typesafe_array_init
- unused_declaration
- unused_import
excluded: excluded:
- Carthage - Carthage
- Pods - Pods
- Generated - Generated
- Localization - "**/Generated"
- "**/Resources"
- ".gem"
- "**/*.app"
line_length: line_length:
warning: 128 warning: 128
@ -105,40 +129,30 @@ identifier_name:
- id - id
- ok - ok
- URL - URL
- qr
- x - x
- y - y
- z - z
warning_threshold: 1 warning_threshold: 1
allow_zero_lintable_files: true
custom_rules: custom_rules:
# General # General
uiwebview_disabled: unsecure_logging:
included: ".*.swift" name: "Unsecure logging"
name: "UIWebView Usage Disabled" regex: '\s(print|debugPrint|NSLog)\('
regex: 'UIWebView' message: "Please use os_log or remove this debug statement"
message: "Do not use UIWebView. Use WKWebView Instead. https://developer.apple.com/reference/uikit/uiwebview"
severity: error
native_print:
name: "print -> DDLog"
regex: '(print|NSLog)\('
message: "Please use CocoaLumberjack instead `print` and `NSlog`"
severity: error
uiedge_insets_zero:
name: "UIEdgeInsets .zero"
regex: '\(top: 0, left: 0, bottom: 0, right: 0\)'
message: "Please use short init `.zero`."
severity: error
let_variable:
name: "Let Variable"
regex: 'var\s\w*(:|(\s=))\sVariable'
message: "Please make variable using `let`."
severity: error severity: error
excluded_match_kinds:
- comment
- comment.mark
- comment.url
- doccomment
- doccomment.field
marks_style: marks_style:
name: "Marks" name: "Marks"
@ -159,19 +173,12 @@ custom_rules:
message: "Type definition not needed" message: "Type definition not needed"
severity: error severity: error
unowned: unsafe_unowned:
name: "Unowned" name: "Unsafe unowned usage"
regex: 'unowned' regex: 'unowned'
message: "Please use `weak` instead. " message: "Please use `weak` instead."
severity: error severity: error
continue_keyword:
name: "Continue"
regex: 'continue'
message: "Don't use continue instruction"
severity: error
match_kinds: keyword
cyrillic_strings: cyrillic_strings:
name: "Cyrillic strings" name: "Cyrillic strings"
regex: '[а-яА-Я]+' regex: '[а-яА-Я]+'
@ -186,26 +193,12 @@ custom_rules:
regex: '(?!\n)[^ \n]+ {2,}.+' regex: '(?!\n)[^ \n]+ {2,}.+'
message: "Remove excess empty spaces" message: "Remove excess empty spaces"
severity: warning severity: warning
match_kinds: excluded_match_kinds:
- argument - comment
- attribute.builtin - comment.mark
- attribute.id - comment.url
- buildconfig.id - doccomment
- buildconfig.keyword - doccomment.field
- identifier
- keyword
- number
- objectliteral
- parameter
- placeholder
# - string # all except string literals
# - comment # and comments
# - comment.mark
# - comment.url
# - doccomment
# - doccomment.field
- string_interpolation_anchor
- typeidentifier
getter_setter_style: getter_setter_style:
name: "Wrong getter/setter code style" name: "Wrong getter/setter code style"
@ -213,49 +206,61 @@ custom_rules:
match_kinds: match_kinds:
- keyword - keyword
message: "Make a new line break when use getter or setter" message: "Make a new line break when use getter or setter"
severity: error severity: warning
redundant_boolean_condition: redundant_boolean_condition:
name: "Redundant Boolean Condition" name: "Redundant Boolean Condition"
regex: "(== true)|(== false)|(!= true)|(!= false)" regex: "(== true)|(== false)|(!= true)|(!= false)"
message: "Comparing a boolean to true is redundant (use `?? false` for optionals), and `!`-syntax is preferred over comparing to false." message: "Comparing a boolean to true is redundant (use `?? false` for optionals), and `!`-syntax is preferred over comparing to false."
severity: error severity: warning
excluded_match_kinds:
- comment
- comment.mark
- comment.url
- doccomment
- doccomment.field
redundant_ternary_operator: redundant_ternary_operator:
name: "Redundant Ternary Operator" name: "Redundant Ternary Operator"
regex: "(\\? true \\: false)|(\\? false \\: true)" regex: "(\\? true \\: false)|(\\? false \\: true)"
message: "Returning a boolean as true is redundant, and `!`-syntax is preferred over returning as false." message: "Returning a boolean as true is redundant, and `!`-syntax is preferred over returning as false."
severity: error severity: warning
single_line_closure: single_line_closure:
name: "Single line closure" name: "Single line closure"
regex: '\{([^\n\/]*\[[^\]]+\][^\n\/]*)?([^\n\/]*[a-zA-Z]\w*(, \w+)*)? in [^\n\/]+' regex: '\{([^\n\/]*\[[^\]]+\][^\n\/]*)?([^\n\/]*[a-zA-Z]\w*(, \w+)*)? in [^\n\/]+'
message: "Too complex expression for single line closure. Improve readability by making it multiline." message: "Too complex expression for single line closure. Improve readability by making it multiline."
severity: error severity: warning
addSubview_in_cell: addSubview_in_cell:
name: "Usage addSubview in cell" name: "Usage addSubview in cell"
regex: '(extension|class)\s*\w+Cell(:| )(?s).*(self\.|\s{2,})add(Subv|V)iews?\(\w' regex: '(extension|class)\s*\w+Cell(:| )(?s).*(self\.|\s{2,})add(Subv|V)iews?\(\w'
message: "Use сontentView instead of self for addSubview or addSubviews methods in cell." message: "Use сontentView instead of self for addSubview or addSubviews methods in cell."
severity: error severity: warning
redundant_type_annotation_bool:
name: "Redundant type annotation for Bool"
regex: '\s((var|let))\s{1,}\w+ *((: *Bool *=)|((\w| |<|>|:)*= *BehaviorRelay<Bool>\( *value *:)) *((true)|(false))'
message: "Using a type annotation for Bool is redundant."
severity: error
parameter_repetition: parameter_repetition:
name: "Parameter repetition" name: "Parameter repetition"
regex: 'func ((\w+([A-Z]\w+))|(\w+)) *(<[^>]+>)? *\( *(?i)(\3|\4):' regex: 'func ((\w+([A-Z]\w+))|(\w+)) *(<[^>]+>)? *\( *(?i)(\3|\4):'
message: "The parameter name is actually used in the function name. Use _ instead." message: "The parameter name is actually used in the function name. Use _ instead."
severity: error severity: warning
parameter_closure: parameter_closure:
name: "Parameter closure" name: "Parameter closure"
regex: '\w*Closure<[^\r\n\t\f\v]*, Void[^\r\n\t\f\v]*>' regex: '\w*Closure<[^\r\n\t\f\v]*, Void[^\r\n\t\f\v]*>'
message: "Use `ParameterClosure` instead of declaring an explicit return value of `Void`." message: "Use `ParameterClosure` instead of declaring an explicit return value of `Void`."
severity: error severity: warning
strong_self:
name: "Strong self"
regex: '(if|guard)\s+let\s+self\s+=\s+self'
message: "Use a local function instead of capture strong self"
severity: warning
pattern_matching:
name: "Pattern matching"
regex: 'case[^\n\(]+\([^\)]*(let|var)\s'
message: "Use a let|var keyword behind parentheses"
severity: warning
# Rx # Rx

View File

@ -3,8 +3,8 @@ file_link=$2
folder=$3 folder=$3
flag_of_delete=$4 flag_of_delete=$4
readonly key_of_delete="--remove-cached" key_of_delete="--remove-cached"
readonly default_folder="./Downloads" default_folder="./Downloads"
if [[ ${folder} = ${key_of_delete} ]]; then if [[ ${folder} = ${key_of_delete} ]]; then
folder="${default_folder}" folder="${default_folder}"

View File

@ -1,14 +1,13 @@
<?php <?php
$PRODUCT_NAME = $argv[1]; $LOCALIZATION_PATH = $argv[1];
$COMMON_STRINGS_PATH = $argv[2]; $COMMON_STRINGS_PATH = $argv[2];
$BUNDLE = $argv[3];
function createFolder($path) { function createFolder($path) {
if (!file_exists($path)) { if (!file_exists($path)) {
mkdir($path, 0777, true); mkdir($path, 0777, true);
} }
} }
$localization = './'.$PRODUCT_NAME.'/Resources/Localization/';
$baseFile = file_get_contents(array_pop(glob($COMMON_STRINGS_PATH.'/default*.json'))); $baseFile = file_get_contents(array_pop(glob($COMMON_STRINGS_PATH.'/default*.json')));
$baseJson = json_decode($baseFile, true); $baseJson = json_decode($baseFile, true);
@ -31,25 +30,26 @@
} }
$ios_strings = preg_replace('/(\\\\)(u)([0-9a-fA-F]{4})/', '$1U$3', $ios_strings); $ios_strings = preg_replace('/(\\\\)(u)([0-9a-fA-F]{4})/', '$1U$3', $ios_strings);
$lproj = $localization.$languageName.'.lproj/'; $lproj = $LOCALIZATION_PATH.$languageName.'.lproj/';
createFolder($lproj); createFolder($lproj);
file_put_contents($lproj.'Localizable.strings', $ios_strings); file_put_contents($lproj.'Localizable.strings', $ios_strings);
if($isBase) { if($isBase) {
createFolder($localization.'Base.lproj/'); createFolder($LOCALIZATION_PATH.'Base.lproj/');
file_put_contents($localization.'Base.lproj/Localizable.strings', $ios_strings); file_put_contents($LOCALIZATION_PATH.'Base.lproj/Localizable.strings', $ios_strings);
$ios_swift_strings = 'import Foundation'.PHP_EOL.PHP_EOL. $ios_swift_strings = 'import Foundation'.PHP_EOL.PHP_EOL.
'// swiftlint:disable superfluous_disable_command'.PHP_EOL. '// swiftlint:disable superfluous_disable_command'.PHP_EOL.
'// swiftlint:disable line_length'.PHP_EOL. '// swiftlint:disable line_length'.PHP_EOL.
'// swiftlint:disable file_length'.PHP_EOL. '// swiftlint:disable file_length'.PHP_EOL.
'// swiftlint:disable cyrillic_strings'.PHP_EOL.
'// swiftlint:disable identifier_name'.PHP_EOL.PHP_EOL. '// swiftlint:disable identifier_name'.PHP_EOL.PHP_EOL.
'public extension String {'.PHP_EOL; 'public extension String {'.PHP_EOL;
foreach ($json as $key=>$value) { foreach ($json as $key=>$value) {
$value_without_linefeed = preg_replace("/\r|\n/", " ", $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; $ios_swift_strings .= "\t/// ".$value_without_linefeed."\n\t".'static let '.preg_replace_callback('/_(.?)/', function ($m) { return strtoupper($m[1]); }, $key).' = NSLocalizedString("'.$key.'", bundle: '.$BUNDLE.', comment: "'.addslashes($value_without_linefeed).'")'."\n".PHP_EOL;
} }
$ios_swift_strings .= '}'.PHP_EOL; $ios_swift_strings .= '}'.PHP_EOL;
file_put_contents($localization.'String+Localization.swift', $ios_swift_strings); file_put_contents($LOCALIZATION_PATH.'String+Localization.swift', $ios_swift_strings);
} }
} }
?> ?>

View File

@ -0,0 +1,39 @@
#!/bin/sh
# Description:
# Add user defined enviroment if programm not found
#
# Parameters:
# $1 - programm
#
# Examples of usage:
# . install_env.sh pmd
#
# When you run Git from the command line, it runs in the environment as set up by your Shell.
# GUI OS X apps, however, have no knowledge about your shell - and the PATH environment can be changed in many different places.
# Export our profile with path by ourselves
function source_home_file {
file="$HOME/$1"
if [[ -f "${file}" ]]; then
if ! source "${file}"; then
export_commands="$(cat "${file}" | grep "^export PATH=")"
while read export_command
do
eval "$export_command"
done <<< "$export_commands"
fi
fi
return 1
}
# Use specific exec due to Xcode has custom value of $PATH
if [ -z "$(which $1)" ]; then
source_home_file ".bash_profile" || source_home_file ".zshrc" || source_home_file ".zprofile" || true
echo "User defined enviroment has been set for ${1}"
fi

14
xcode/bootstrap/Brewfile Normal file
View File

@ -0,0 +1,14 @@
# Working environment
brew "rbenv" # ruby + bundler
brew "gettext"
# Code, configs and project generation
brew "php"
brew "python"
brew "xcodegen"
# code quality
brew "pmd"
# CI badge
# brew "imagemagick"

9
xcode/bootstrap/Gemfile Normal file
View File

@ -0,0 +1,9 @@
source "https://rubygems.org"
gem "cocoapods"
gem "fastlane"
gem 'mustache' # for config generator
gem 'xcode-install'
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

91
xcode/bootstrap/Makefile Normal file
View File

@ -0,0 +1,91 @@
GREEN := $(shell tput -Txterm setaf 2)
YELLOW := $(shell tput -Txterm setaf 3)
WHITE := $(shell tput -Txterm setaf 7)
RESET := $(shell tput -Txterm sgr0)
RUBY_VERSION="2.7.6"
open_project=(open *.xcworkspace)
install_dev_certs=(bundle exec fastlane InstallDevelopmentSigningIdentities)
install_pods=(bundle exec pod install || bundle exec pod install --repo-update)
init_rbenv=(if command -v rbenv &> /dev/null; then eval "$$(rbenv init -)"; fi)
TARGET_MAX_CHAR_NUM=20
## Show help
help:
@echo ''
@echo 'Использование:'
@echo ' ${YELLOW}make${RESET} ${GREEN}<target>${RESET}'
@echo ''
@echo 'Команды:'
@awk '/^[a-zA-Z\-\_0-9]+:/ { \
helpMessage = match(lastLine, /^## (.*)/); \
if (helpMessage) { \
helpCommand = substr($$1, 0, index($$1, ":")-1); \
helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
printf " ${YELLOW}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${GREEN}%s${RESET}\n", helpCommand, helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST)
## Инициализирует проект и устанавливает системные утилиты
init:
brew bundle
$(call init_rbenv)
rbenv install -s ${RUBY_VERSION}
rbenv global ${RUBY_VERSION}
if ! gem spec bundler > /dev/null 2>&1; then\
echo "bundler gem is not installed!";\
-sudo gem install bundler;\
fi
bundle install
xcodegen
$(call install_pods)
bundle exec fastlane install_plugins
$(call install_dev_certs)
$(call open_project)
git config --local core.hooksPath .githooks
## Устанавливает поды
pod:
$(call install_pods)
## Запускает генерацию файла проекта
gen:
xcodegen
## Устанавливает сертификат и профили для запуска на девайсе
dev_certs:
$(call install_dev_certs)
## Открывает папку для ручного редактирования сертификатов и профайлов
update_certs:
bundle exec fastlane ManuallyUpdateCodeSigning
## Поднимает версию приложения (параметр "X.Y.Z")
bumpAppVersion:
ifeq ($(version),undefined)
@echo "Version parameter is missing (ex: x.y.z)" $(target)
else
bundle exec fastlane run increment_version_number version_number:$(version)
endif
## Позволяет быстро открыть workspace проекта
start:
$(call open_project)
## Очищает содержимое папки DerivedData
clean:
rm -rf ~/Library/Developer/Xcode/DerivedData/*

View File

@ -0,0 +1,25 @@
#!/bin/sh
# Description:
# Runs full linting and copy-paste-detection for project
#
# Required environment variables:
# SRCROOT - project directory.
# SCRIPT_DIR - directory of current script.
#
# Optional environment variables:
# See swiftlint.sh and copy_paste_detection.sh for complete list of available variables
#
# Example of usage:
# ./full_code_lint.sh
#
if [ -z "${SCRIPT_DIR}" ]; then
SCRIPT_DIR=${SRCROOT}/build-scripts/xcode/build_phases
fi
. ${SRCROOT}/build-scripts/xcode/aux_scripts/install_env.sh swiftlint
FORCE_LINT=true; . ${SCRIPT_DIR}/swiftlint.sh
. ${SRCROOT}/build-scripts/xcode/aux_scripts/install_env.sh cpd
. ${SCRIPT_DIR}/copy_paste_detection.sh Localization Generated Pods

View File

@ -0,0 +1,22 @@
#!/bin/sh
# Description:
# Runs incremental linting for project
#
# Required environment variables:
# SRCROOT - project directory.
# SCRIPT_DIR - directory of current script.
#
# Optional environment variables:
# See swiftlint.sh for complete list of available variables
#
# Example of usage:
# ./incremetal_code_lint.sh
#
if [ -z "${SCRIPT_DIR}" ]; then
SCRIPT_DIR=${SRCROOT}/build-scripts/xcode/build_phases
fi
. ${SRCROOT}/build-scripts/xcode/aux_scripts/install_env.sh swiftlint
. ${SCRIPT_DIR}/swiftlint.sh

6
xcode/bootstrap/setup.command Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PROJECT_DIR="${DIR}/../../../"
make init -C ${PROJECT_DIR}

355
xcode/build_phases/api_generator.sh Normal file → Executable file
View File

@ -1,9 +1,350 @@
VERSION=$1 #!/bin/sh
FILE_NAME="api-generator-${VERSION}.jar"
# download api generator # Description:
link="https://dl.bintray.com/touchin/touchin-tools/ru/touchin/api-generator/${VERSION}/${FILE_NAME}" # Generates API models & methods.
. build-scripts/xcode/aux_scripts/download_file.sh ${FILE_NAME} ${link} #
# Parameters:
# $1 - api generator version.
# $2 - path to generated code directory
#
# Required environment variables:
# SRCROOT - path to project folder.
#
# Optional environment variables:
# OUTPUT_PATH - path to Generated folder.
# API_SPEC_DIR - path to api specification folder
# VERBOSE - print debug messages
# API_NAME - project name that will be used by generator (example: OUTPUT_PATH/API_NAME/Classes )
#
# Examples of usage:
# . api_generator.sh 1.4.0-beta1
# . api_generator.sh 1.4.0-beta1 ${TARGET_NAME}/Generated
#
# execute api generator readonly EXIT_SUCCESS=0
java -Xmx6g -jar "Downloads/${FILE_NAME}" generate-client-code --output-language SWIFT --specification-path common/api --output-path ${PRODUCT_NAME}/Generated --single-file true readonly EXIT_FAILURE=1
readonly TRUE=1
readonly FALSE=0
readonly LOG_TAG="API-GENERATOR"
notice()
{
echo "${LOG_TAG}:NOTICE: ${1}" >&2
}
debug()
{
if [ ! -z "${VERBOSE}" ]; then
echo "${LOG_TAG}:DEBUG: ${1}" >&2
fi
}
exit_on_failure()
{
eval ${1}
local -r EXIT_CODE=$?
if [ ${EXIT_CODE} -ne 0 ]; then
echo "Recent command: \`${1}\` failed with code ${EXIT_CODE}"
exit ${EXIT_CODE}
fi
}
is_force_run()
{
if [ -z "${FORCE_RUN}" ]; then
echo ${FALSE}
return
fi
local -r STR_MODE=`tr "[:upper:]" "[:lower:]" <<< ${FORCE_RUN}`
if [ ${STR_MODE} == "yes" ] || [ ${STR_MODE} == "true" ] || [ ${STR_MODE} == "1" ]; then
echo ${TRUE}
else
echo ${FALSE}
fi
}
is_single_file()
{
if [ -z "${SINGLE_FILE}" ]; then
echo "true"
return
fi
local -r STR_MODE=`tr "[:upper:]" "[:lower:]" <<< ${SINGLE_FILE}`
if [ ${STR_MODE} == "no" ] || [ ${STR_MODE} == "false" ] || [ ${STR_MODE} == "0" ]; then
echo "false"
else
echo "true"
fi
}
get_api_spec_current_commit()
{
if [ -z "${API_SPEC_DIR}" ]; then
if [ ! -z "${1}" ]; then
echo `git -C ${1} rev-parse --verify HEAD`
else
echo `git rev-parse --verify HEAD`
fi
else
echo `git -C ${API_SPEC_DIR} rev-parse --verify HEAD`
fi
}
get_api_spec_status()
{
if [ -z "${API_SPEC_DIR}" ]; then
if [ ! -z "${1}" ]; then
echo `git -C ${1} status -s`
else
echo `git status -s`
fi
else
echo `git -C ${API_SPEC_DIR} status -s`
fi
}
is_api_spec_under_source_control()
{
local IS_UNDER_SOURCE_CONTROL_CHECK
if [ -z "${API_SPEC_DIR}" ]; then
if [ ! -z "${1}" ]; then
IS_UNDER_SOURCE_CONTROL_CHECK=`git -C ${1} rev-parse --is-inside-work-tree 2>/dev/null`
else
IS_UNDER_SOURCE_CONTROL_CHECK=`git rev-parse --is-inside-work-tree 2>/dev/null`
fi
else
IS_UNDER_SOURCE_CONTROL_CHECK=`git -C ${API_SPEC_DIR} rev-parse --is-inside-work-tree 2>/dev/null`
fi
if [ "${IS_UNDER_SOURCE_CONTROL_CHECK}" = "true" ]; then
echo ${TRUE}
else
echo ${FALSE}
fi
}
is_api_spec_has_uncommited_changes()
{
if [ `is_api_spec_under_source_control` -eq ${TRUE} ]; then
local -r API_SPEC_STATUS=`get_api_spec_status`
if [ -z "${API_SPEC_STATUS}" ]; then
echo ${FALSE}
else
echo ${TRUE}
fi
else
echo ${FALSE}
fi
}
is_nothing_changed_since_last_check()
{
if [ `is_force_run` -eq ${TRUE} ]; then
notice "Force run detected. Skipping commits comparison."
echo ${TRUE}
fi
if [ -z "${COMMIT_FILE_PATH}" ]; then
if [ ! -z "${1}" ]; then
local -r COMMIT_FILE_PATH=${1}
else
debug "COMMIT_FILE_PATH should be defined or passed as first argument!"
echo ${FALSE}
fi
fi
if [ `is_api_spec_under_source_control` -eq ${TRUE} ]; then
local -r CURRENT_COMMIT=`get_api_spec_current_commit`
local -r LAST_CHECKED_COMMIT=`cat ${COMMIT_FILE_PATH} 2> /dev/null || echo ""`
if [ ${CURRENT_COMMIT} = "${LAST_CHECKED_COMMIT}" ]; then
if [ `is_api_spec_has_uncommited_changes` -eq ${TRUE} ]; then
notice "API spec has uncomitted changes."
echo ${FALSE}
else
echo ${TRUE}
fi
else
echo ${FALSE}
fi
else
echo ${FALSE}
fi
}
record_current_commit()
{
if [ `is_force_run` -eq ${TRUE} ]; then
notice "Force run detected. Commit won't be recorder."
exit ${EXIT_SUCCESS}
fi
if [ -z "${COMMIT_FILE_PATH}" ]; then
if [ ! -v "${1}" ]; then
local -r COMMIT_FILE_PATH=${1}
else
debug "COMMIT_FILE_PATH should be defined or passed as second argument!"
return ${EXIT_FAILURE}
fi
fi
local -r CURRENT_COMMIT=`get_api_spec_current_commit`
echo ${CURRENT_COMMIT} > ${COMMIT_FILE_PATH}
}
openapi_codegen()
{
if [ -z "${OPEN_API_SPEC_PATH}" ]; then
if [ ! -v "${1}" ]; then
local -r OPEN_API_SPEC_PATH=${1}
else
debug "OPEN_API_SPEC_PATH should be defined or passed as first argument!"
return ${EXIT_FAILURE}
fi
fi
if [ -z "${OUTPUT_PATH}" ]; then
if [ ! -v "${2}" ]; then
local -r OUTPUT_PATH=${2}
else
debug "OUTPUT_PATH should be defined or passed as second argument!"
return ${EXIT_FAILURE}
fi
fi
if [ -z "${VERSION}" ]; then
if [ ! -v "${3}" ]; then
local -r VERSION=${3}
else
debug "VERSION should be defined or passed as third argument!"
return ${EXIT_FAILURE}
fi
fi
if [ -z "${API_NAME}" ]; then
local -r API_NAME="${PROJECT_NAME}API"
fi
notice "OpenAPI spec generation for ${OPEN_API_SPEC_PATH}"
local -r CODEGEN_VERSION="3.0.34"
local -r CODEGEN_FILE_NAME="swagger-codegen-cli-${CODEGEN_VERSION}.jar"
local -r CODEGEN_DOWNLOAD_URL="https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/${CODEGEN_VERSION}/${CODEGEN_FILE_NAME}"
. build-scripts/xcode/aux_scripts/download_file.sh ${CODEGEN_FILE_NAME} ${CODEGEN_DOWNLOAD_URL}
local -r TINETWORKING_CODEGEN_FILE_NAME="codegen-${VERSION}.jar"
local -r DOWNLOAD_URL="https://maven.dev.touchin.ru/ru/touchin/codegen/${VERSION}/${TINETWORKING_CODEGEN_FILE_NAME}"
. build-scripts/xcode/aux_scripts/download_file.sh ${TINETWORKING_CODEGEN_FILE_NAME} ${DOWNLOAD_URL}
rm -rf ${OUTPUT_PATH}/${API_NAME} # remove previously generated API (if exists)
local -r OPENAPI_COMMAND="java -cp "Downloads/${CODEGEN_FILE_NAME}:Downloads/${TINETWORKING_CODEGEN_FILE_NAME}" io.swagger.codegen.v3.cli.SwaggerCodegen generate -l TINetworking -i ${OPEN_API_SPEC_PATH} -o ${OUTPUT_PATH} --additional-properties projectName=${API_NAME}"
exit_on_failure "${OPENAPI_COMMAND}"
# flatten folders hierarchy
mv ${OUTPUT_PATH}/${API_NAME}/Classes/Swaggers/* ${OUTPUT_PATH}/${API_NAME}/
rm -rf ${OUTPUT_PATH}/${API_NAME}/Classes
}
api_generator_codegen()
{
if [ -z "${API_SPEC_DIR}" ]; then
if [ ! -v "${1}" ]; then
local -r API_SPEC_DIR=${1}
else
debug "API_SPEC_DIR should be defined or passed as first argument!"
return ${EXIT_FAILURE}
fi
fi
if [ -z "${OUTPUT_PATH}" ]; then
if [ ! -v "${2}" ]; then
local -r OUTPUT_PATH=${2}
else
debug "OUTPUT_PATH should be defined or passed as second argument!"
return ${EXIT_FAILURE}
fi
fi
if [ -z "${VERSION}" ]; then
if [ ! -v "${3}" ]; then
local -r VERSION=${3}
else
debug "VERSION should be defined or passed as third argument!"
return ${EXIT_FAILURE}
fi
fi
notice "api-generator spec generation for ${API_SPEC_DIR}/main.json"
local -r FILE_NAME="api-generator-${VERSION}.jar"
local -r DOWNLOAD_URL="https://maven.dev.touchin.ru/ru/touchin/api-generator/${VERSION}/${FILE_NAME}"
. build-scripts/xcode/aux_scripts/download_file.sh ${FILE_NAME} ${DOWNLOAD_URL}
local -r API_GENERATOR_COMMAND="java -Xmx12g -jar Downloads/${FILE_NAME} generate-client-code --output-language SWIFT --specification-path ${API_SPEC_DIR} --output-path ${OUTPUT_PATH} --single-file $(is_single_file)"
exit_on_failure "${API_GENERATOR_COMMAND}"
}
readonly BUILD_PHASES_DIR=${SRCROOT}/build_phases
mkdir -p ${BUILD_PHASES_DIR}
readonly COMMIT_FILE_PATH=${BUILD_PHASES_DIR}/api-generator-commit
if [ `is_nothing_changed_since_last_check` -eq ${TRUE} ]; then
notice "Nothing was changed. API generation skipped."
exit ${EXIT_SUCCESS}
fi
readonly VERSION=$1
if [ -z "${OUTPUT_PATH}" ]; then
if [ ! -z "${2}" ]; then
readonly OUTPUT_PATH=${2}
else
readonly OUTPUT_PATH="Generated"
fi
fi
if [ -z "${API_SPEC_DIR}" ]; then
readonly API_SPEC_DIR="common/api"
fi
mkdir -p ${OUTPUT_PATH}
readonly OPEN_API_SPEC_PATH=`find ${API_SPEC_DIR} -maxdepth 1 -name '*.yaml' -o -name '*.yml' | head -n 1`
if [ -f "${OPEN_API_SPEC_PATH}" ]; then
openapi_codegen
elif [ -f "${API_SPEC_DIR}/main.json" ]; then
api_generator_codegen
else
notice "No api spec found!"
exit ${EXIT_FAILURE}
fi
if [ $? -ne ${EXIT_FAILURE} ]; then
record_current_commit
fi

View File

@ -0,0 +1,89 @@
#!/bin/sh
# Description:
# Converts SCRIPT_INPUT_FILE_{N} or SCRIPT_INPUT_FILE_LIST_{N} variables to string that contains
# list of file names splitted by given separator.
#
# Parameters:
# $1 - separator to use.
# $2 - default value to return if SCRIPT_INPUT_FILE_COUNT or SCRIPT_INPUT_FILE_LIST_COUNT is zero.
#
# Optional environment variables:
# FILE_NAMES_SEPARATOR - separator to use.
# DEFAULT_FILE_NAMES - default value if was found in environment variables.
# SCRIPT_INPUT_FILE_COUNT - number of files listed in "Input files" section of build phase.
# SCRIPT_INPUT_FILE_{N} - file path of specific input file at index.
# SCRIPT_INPUT_FILE_LIST_COUNT - number of files listed in "Input File Lists" section of build phase.
# SCRIPT_INPUT_FILE_LIST_{N} - file path to specifis xcfilelist file at index.
#
# Examples of usage:
# read_input_file_names
# read_input_file_names.sh " " path/to/project
#
has_input_files()
{
[ ! -z "${SCRIPT_INPUT_FILE_COUNT}" ] && [ ${SCRIPT_INPUT_FILE_COUNT} -gt 0 ]
}
has_input_file_lists()
{
[ ! -z "${SCRIPT_INPUT_FILE_LIST_COUNT}" ] && [ ${SCRIPT_INPUT_FILE_LIST_COUNT} -gt 0 ]
}
if [ -z "${FILE_NAMES_SEPARATOR}" ]; then
if [ ! -z "${1}" ]; then
FILE_NAMES_SEPARATOR=${1}
else
FILE_NAMES_SEPARATOR=" "
fi
fi
if [ -z "${DEFAULT_FILE_NAMES}" ]; then
if [ ! -z "${2}" ]; then
DEFAULT_FILE_NAMES=${2}
else
DEFAULT_FILE_NAMES=""
fi
fi
INPUT_FILE_NAMES=""
if has_input_files && has_input_file_lists; then
>&2 echo "Passing Input Files and Input Files Lists is not supported!\nOnly Input Files will be used."
fi
if has_input_files && \
[ ${SCRIPT_INPUT_FILE_COUNT} -gt 0 ]; then
for i in `seq 0 $((${SCRIPT_INPUT_FILE_COUNT}-1))`
do
SCRIPT_INPUT_FILE_VARIABLE_NAME="SCRIPT_INPUT_FILE_${i}"
SHELL_VARIABLE="\${${SCRIPT_INPUT_FILE_VARIABLE_NAME}}"
RESOLVED_FILE_NAME=`envsubst <<< ${SHELL_VARIABLE}`
if [ ! -z ${INPUT_FILE_NAMES} ]; then
INPUT_FILE_NAMES=${INPUT_FILE_NAMES}${FILE_NAMES_SEPARATOR}
else
INPUT_FILE_NAMES=${INPUT_FILE_NAMES}${FILE_NAMES_SEPARATOR}${RESOLVED_FILE_NAME}
fi
done
elif has_input_file_lists; then
for i in `seq 0 $((${SCRIPT_INPUT_FILE_LIST_COUNT}-1))`
do
SCRIPT_INPUT_FILE_LIST_VARIABLE_NAME="SCRIPT_INPUT_FILE_LIST_${i}"
SHELL_VARIABLE="\${${SCRIPT_INPUT_FILE_LIST_VARIABLE_NAME}}"
FILE_NAME=`envsubst <<< ${SHELL_VARIABLE}`
RESOLVED_FILE_NAMES=`envsubst < ${FILE_NAME}`
for INPUT_FILE_NAME in ${RESOLVED_FILE_NAMES}; do
INPUT_FILE_NAMES=${INPUT_FILE_NAMES}${INPUT_FILE_NAME}${FILE_NAMES_SEPARATOR}
done
done
fi
if [ -z "${INPUT_FILE_NAMES}" ]; then
echo ${DEFAULT_FILE_NAMES}
else
echo ${INPUT_FILE_NAMES}
fi

Binary file not shown.

65
xcode/build_phases/copy_paste_detection.sh Normal file → Executable file
View File

@ -1,20 +1,65 @@
#!/bin/sh
# Description:
# Validates code for copy-paste, prints results to standard output and report file.
#
# Parameters:
# $1 $2 $3 $n - folders to exclude from code checking.
#
# Required environment variables:
# SRCROOT - project directory.
# SCRIPT_DIR - directory of current script.
#
# Optional environment variables:
# SCRIPT_INPUT_FILE_COUNT - number of files listed in "Input files" of build phase.
# SCRIPT_INPUT_FILE_{N} - file path to directory that should be checked.
#
# Modified files:
# ${SRCROOT}/code-quality-reports/CPDLog.txt - check report.
#
# Example of usage:
# copy_paste_detection.sh Generated Localization Pods
#
EXIT_SUCCESS=0
EXIT_FAILURE=1
if which pmd >/dev/null; then if which pmd >/dev/null; then
# running CPD REPORTS_DIR="${SRCROOT}/code-quality-reports"
readonly SOURCES_DIR=${1:-${PROJECT_DIR}} # first argument or PROJECT_DIR
readonly REPORTS_DIR=${PROJECT_DIR}/code-quality-reports
readonly FILES_TO_EXCLUDE=`find ${SOURCES_DIR} -type d -name Localization -or -name Generated -or -name Carthage -or -name Pods | paste -sd " " -`
mkdir ${REPORTS_DIR} SOURCES_DIRS=`. ${SCRIPT_DIR}/common/read_input_file_names.sh " " ${SRCROOT}`
pmd cpd --files ${SOURCES_DIR} --exclude ${FILES_TO_EXCLUDE} --minimum-tokens 50 --language swift --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer > ${REPORTS_DIR}/cpd-output.xml --failOnViolation true COMMAND_LINE_ARGUMENTS=$@
php ./build-scripts/xcode/aux_scripts/cpd_script.php ${REPORTS_DIR}/cpd-output.xml | tee ${REPORTS_DIR}/CPDLog.txt FOLDERS_TO_EXCLUDE=""
# Make paths relative to SOURCES_DIR, so different developers won't rewrite entire file for argument in ${COMMAND_LINE_ARGUMENTS}
readonly SED_REPLACEMENT_STRING=$(echo ${SOURCES_DIR} | sed "s/\//\\\\\//g") do
FOLDERS_TO_EXCLUDE=${FOLDERS_TO_EXCLUDE}"-or -name ${argument} "
done
FOLDERS_TO_EXCLUDE=`echo ${FOLDERS_TO_EXCLUDE} | cut -c5-` # remove first "-or"
FILES_TO_EXCLUDE=`find ${SRCROOT} -type d ${FOLDERS_TO_EXCLUDE} | paste -sd " " -`
mkdir -p ${REPORTS_DIR}
DIRS_ARGUMENTS=""
for SOURCE_DIR in ${SOURCES_DIRS}; do
DIRS_ARGUMENTS=${DIRS_ARGUMENTS}" --dir "${SOURCE_DIR}
done
pmd cpd ${DIRS_ARGUMENTS} --exclude ${FILES_TO_EXCLUDE} --minimum-tokens 50 --language swift --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer --skip-lexical-errors true > ${REPORTS_DIR}/cpd-output.xml
php ${SCRIPT_DIR}/../aux_scripts/cpd_script.php ${REPORTS_DIR}/cpd-output.xml | tee ${REPORTS_DIR}/CPDLog.txt
# Make paths relative to SRCROOT, so different developers won't rewrite entire file
SED_REPLACEMENT_STRING=$(echo ${SRCROOT} | sed "s/\//\\\\\//g")
sed -i '' "s/${SED_REPLACEMENT_STRING}//g" "${REPORTS_DIR}/CPDLog.txt" sed -i '' "s/${SED_REPLACEMENT_STRING}//g" "${REPORTS_DIR}/CPDLog.txt"
else else
echo "warning: pmd not installed, install using 'brew install pmd'" echo "warning: pmd not installed, install using 'brew install pmd'"
exit 1
exit ${EXIT_FAILURE}
fi fi

View File

@ -0,0 +1,22 @@
require 'yaml'
require_relative '../../managers/managers'
require_relative '../../templates/templates'
# Input files paths
build_settings_file_path = ARGV[0]
generated_features_enum_file_path = ARGV[1]
build_settings_features_list = Managers::FileManager.load_from_file_YAML(build_settings_file_path)["features"]
if build_settings_features_list.nil? or build_settings_features_list.empty?
raise "There are no features in " + build_settings_file_path
end
# Generate enum Feature Toggles
features_enum_template = Templates::FeatureTemplates.features_enum
utils = Managers::TemplateManager.new(build_settings_features_list)
rendered_enum = utils.render(features_enum_template).strip
Managers::FileManager.save_data_to_file(generated_features_enum_file_path, rendered_enum)

View File

@ -0,0 +1,19 @@
# Input paths
readonly BUILD_SETTINGS_FILE_PATH=${1:-${PROJECT_DIR}/common/build_settings.yaml}
readonly FEATURES_ENUM_FILE_PATH=${2:-${PROJECT_DIR}/${PRODUCT_NAME}/Resources/Features/Feature.swift}
# Features enunm generator script
readonly CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
readonly GENERATOR_SCRIPT=${CURRENT_DIR}/features_generator.rb
if ! [ -e ${BUILD_SETTINGS_FILE_PATH} ]; then
echo "File ${BUILD_SETTINGS_FILE_PATH} does not exist. Add this file and try again."
exit 1
fi
if ! [ -e ${FEATURES_ENUM_FILE_PATH} ]; then
echo "File ${FEATURES_ENUM_FILE_PATH} does not exist. Add this file and try again."
exit 1
fi
ruby ${GENERATOR_SCRIPT} ${BUILD_SETTINGS_FILE_PATH} ${FEATURES_ENUM_FILE_PATH}

View File

@ -1,16 +1,47 @@
LOCALIZATION_PATH="${PRODUCT_NAME}/Resources/Localization" #!/bin/sh
#first argument set strings folder path
# Description:
# Generates Localizeable.strings and String+Localization.swift files.
#
# Parameters:
# $1 - path to strings folder containing json files.
# $2 - path to Localization folder (output).
# $3 - Bundle for localization. Default is `.main`.
#
# Required environment variables:
# SCRIPT_DIR - directory of current script.
#
# Optional environment variables:
# PRODUCT_NAME - product name to produce path to localization folder (output).
#
# Examples of usage:
# . localization.sh
# . localization.sh common/strings Resources/Localization/ .main
#
readonly EXIT_SUCCESS=0
readonly EXIT_FAILURE=1
. ${SCRIPT_DIR}/../aux_scripts/install_env.sh php
STRINGS_FOLDER=${1:-"common/strings"} STRINGS_FOLDER=${1:-"common/strings"}
LOCALIZATION_PATH=${2:-"${PRODUCT_NAME}/Resources/Localization/"}
BUNDLE=${3:-".main"}
if ! [ -e ${LOCALIZATION_PATH} ]; then if ! [ -e ${LOCALIZATION_PATH} ]; then
echo "${PROJECT_DIR}/${LOCALIZATION_PATH} path does not exist. Add these folders and try again." echo "${LOCALIZATION_PATH} path does not exist. Add these folders and try again."
exit 1 exit ${EXIT_FAILURE}
fi fi
if ! [ -e "${PROJECT_DIR}/${STRINGS_FOLDER}" ]; then if ! [ -e "${STRINGS_FOLDER}" ]; then
echo "${PROJECT_DIR}/${STRINGS_FOLDER} path does not exist. Submodule with strings should be named common and contain strings folder." echo "${STRINGS_FOLDER} path does not exist. Submodule with strings should be named common and contain strings folder."
exit 1 exit ${EXIT_FAILURE}
fi fi
#second argument set strings script path if which php >/dev/null; then
php ${2:-build-scripts/xcode/aux_scripts/import_strings.php} ${PRODUCT_NAME} ${STRINGS_FOLDER} php ${SCRIPT_DIR}/../aux_scripts/import_strings.php ${LOCALIZATION_PATH} ${STRINGS_FOLDER} ${BUNDLE}
else
echo "warning: php not installed, install using 'brew install php'"
exit ${EXIT_FAILURE}
fi

View File

@ -7,17 +7,50 @@ class SettingOption
def initialize def initialize
@options = OpenStruct.new @options = OpenStruct.new
OptionParser.new do |opt| OptionParser.new do |opt|
opt.on('-p', '--project_root_path STRING', 'The path of project directory and contains *.xcodeproj file always. ' + opt.on('-p',
'Example: project_root_path=~/Projects/MyProject/Source/..') { |option| @options.project_root_path = option } '--project_root_path STRING',
opt.on('-r', '--source_root_path STRING', 'The path of source directory and may not contains *.xcodeproj file in some cases. ' + 'The path of project directory and contains *.xcodeproj file always. ' +
'Example: source_root_path=~/Projects/MyProject/') { |option| @options.source_root_path = option } 'Example: project_root_path=~/Projects/MyProject/Source/..') { |option|
opt.on('-s', '--swiftlint_executable_path STRING', 'The executable path of swiftlint') { |option| @options.swiftlint_executable_path = option } @options.project_root_path = option
opt.on('-c', '--check_mode MODE', 'The mode of check is "fully" or "simplified"') { |option| @options.check_mode = option } }
opt.on('-u', '--use_multiple BOOL', 'The flag indicates the use of multiple yaml swiftlint configurations') { |option| @options.use_multiple = option } opt.on('-r',
opt.on('-d', '--source_date DATE', 'The date of grouping files according touchin and old swiftlint rules') { |option| @options.source_date = option } '--source_root_path STRING',
opt.on('-y', '--touchin_swiftlint_yaml_path STRING', 'The path to the touchin swiftlint yaml relative to the source directory') { |option| @options.touchin_swiftlint_yaml_path = option } 'The path of source directory and may not contains *.xcodeproj file in some cases. ' +
'Example: source_root_path=~/Projects/MyProject/') { |option|
@options.source_root_path = option
}
opt.on('-s',
'--swiftlint_executable_path STRING',
'The executable path of swiftlint') { |option|
@options.swiftlint_executable_path = option
}
opt.on('-c',
'--check_mode MODE',
'The mode of check is "fully" or "simplified"') { |option|
@options.check_mode = option
}
opt.on('-u',
'--use_multiple BOOL',
'The flag indicates the use of multiple yaml swiftlint configurations') { |option|
@options.use_multiple = option
}
opt.on('-d',
'--source_date DATE',
'The date of grouping files according touchin and old swiftlint rules') { |option|
@options.source_date = option
}
opt.on('-tc',
'--touchin_swiftlint_yaml_path STRING',
'The path to the touchin swiftlint yaml relative to the source directory') { |option|
@options.touchin_swiftlint_yaml_path = option
}
opt.on('-oc',
'--old_swiftlint_yaml_path STRING',
'The path to the old swiftlint yaml relative to the source directory') { |option|
@options.old_swiftlint_yaml_path = option
}
end.parse! end.parse!
if @options.check_mode.to_s.nilOrEmpty? if @options.check_mode.to_s.nilOrEmpty?
@options.check_mode = 'fully' @options.check_mode = 'fully'
end end
@ -29,37 +62,17 @@ class SettingOption
if @options.source_root_path.to_s.nilOrEmpty? if @options.source_root_path.to_s.nilOrEmpty?
@options.source_root_path = @options.project_root_path @options.source_root_path = @options.project_root_path
end end
if @options.touchin_swiftlint_yaml_path.to_s.nilOrEmpty? if @options.touchin_swiftlint_yaml_path.to_s.nilOrEmpty?
@options.touchin_swiftlint_yaml_path = '/build-scripts/xcode/.swiftlint.yml' @options.touchin_swiftlint_yaml_path = File.join(project_root_path, 'build-scripts/xcode/.swiftlint.yml')
end
if @options.old_swiftlint_yaml_path.to_s.nilOrEmpty?
@options.old_swiftlint_yaml_path = File.join(project_root_path, '.swiftlint.yml')
end end
end end
def project_root_path def method_missing(method, *args, &block)
@options.project_root_path @options.send(method, *args, &block)
end
def source_date
@options.source_date
end
def swiftlint_executable_path
@options.swiftlint_executable_path
end
def check_mode
@options.check_mode
end
def use_multiple
@options.use_multiple
end
def source_root_path
@options.source_root_path
end
def touchin_swiftlint_yaml_path
@options.touchin_swiftlint_yaml_path
end end
end end

View File

@ -1,4 +1,5 @@
require 'fileutils' require 'fileutils'
require 'tmpdir'
require_relative 'array_extension.rb' require_relative 'array_extension.rb'
require_relative 'git_caretaker.rb' require_relative 'git_caretaker.rb'
@ -7,19 +8,19 @@ require_relative 'swift_file_manager.rb'
require_relative 'yaml_manager.rb' require_relative 'yaml_manager.rb'
class StrategyMaker class StrategyMaker
def initialize(project_root_path, swiftlint_executable_path, touchin_swiftlint_yaml_path) def initialize(project_root_path, swiftlint_executable_path, touchin_swiftlint_yaml_path, old_swiftlint_yaml_path)
@project_root_path = project_root_path @project_root_path = project_root_path
@touchin_swiftlint_yaml_path = project_root_path + touchin_swiftlint_yaml_path @touchin_swiftlint_yaml_path = touchin_swiftlint_yaml_path
@old_swiftlint_yaml_path = project_root_path + '/.swiftlint.yml' @old_swiftlint_yaml_path = old_swiftlint_yaml_path
@temporary_swiftlint_folder_name = project_root_path + '/temporary_swiftlint' @temporary_swiftlint_folder_name = Dir.mktmpdir
@touchin_swiftlint_yaml_temporary_path = @temporary_swiftlint_folder_name + '/.touchin_swiftlint.yml' @touchin_swiftlint_yaml_temporary_path = File.join(@temporary_swiftlint_folder_name, '.touchin_swiftlint.yml')
@old_swiftlint_yaml_temporary_path = @temporary_swiftlint_folder_name + '/.old_swiftlint.yml' @old_swiftlint_yaml_temporary_path = File.join(@temporary_swiftlint_folder_name, '.old_swiftlint.yml')
@swiftlint_autocorrect_command = swiftlint_executable_path + ' autocorrect --path ' + @project_root_path + ' --config ' @swiftlint_autocorrect_command = swiftlint_executable_path + ' autocorrect --path ' + @project_root_path + ' --config '
@swiftlint_lint_command = swiftlint_executable_path + ' --path ' + @project_root_path + ' --config ' @swiftlint_lint_command = swiftlint_executable_path + ' --path ' + @project_root_path + ' --config '
end end
def run_fully_multiple_strategy(source_date) def run_fully_multiple_strategy(source_date)
create_yaml_managers_and_copy_temporary_files create_yaml_managers_and_copy_temporary_files
@ -33,38 +34,38 @@ class StrategyMaker
@touchin_swiftlint_yaml_manager.update('excluded', total_touchin_excluded_files) @touchin_swiftlint_yaml_manager.update('excluded', total_touchin_excluded_files)
@old_swiftlint_yaml_manager.update('excluded', total_old_excluded_files) @old_swiftlint_yaml_manager.update('excluded', total_old_excluded_files)
run_multiple_strategy(@touchin_swiftlint_yaml_temporary_path, @old_swiftlint_yaml_temporary_path) run_multiple_strategy(@touchin_swiftlint_yaml_temporary_path, @old_swiftlint_yaml_temporary_path)
end end
def run_simplified_multiple_strategy(source_date, source_root_path) def run_simplified_multiple_strategy(source_date, source_root_path)
included_files = GitСaretaker.get_modified_files included_files = GitСaretaker.get_modified_files
if included_files.nilOrEmpty? if included_files.nilOrEmpty?
puts 'Git did not found swift files to check' puts 'Git did not found swift files to check'
return return
end end
create_yaml_managers_and_copy_temporary_files create_yaml_managers_and_copy_temporary_files
exclude_files = unique_exclude_files(@touchin_swiftlint_yaml_manager, @old_swiftlint_yaml_manager) exclude_files = unique_exclude_files(@touchin_swiftlint_yaml_manager, @old_swiftlint_yaml_manager)
included_files = included_files.map { |file_path| source_root_path + file_path } included_files = included_files.map { |file_path| source_root_path + file_path }
swift_file_manager = SwiftFileManager.new(exclude_files, source_date) swift_file_manager = SwiftFileManager.new(exclude_files, source_date)
swift_file_manager.find_list_file_paths_from(included_files) swift_file_manager.find_list_file_paths_from(included_files)
total_touchin_included_files = swift_file_manager.new_files total_touchin_included_files = swift_file_manager.new_files
total_old_included_files = swift_file_manager.old_files total_old_included_files = swift_file_manager.old_files
@touchin_swiftlint_yaml_manager.update('excluded', []) @touchin_swiftlint_yaml_manager.update('excluded', [])
@old_swiftlint_yaml_manager.update('excluded', []) @old_swiftlint_yaml_manager.update('excluded', [])
@touchin_swiftlint_yaml_manager.update('included', total_touchin_included_files) @touchin_swiftlint_yaml_manager.update('included', total_touchin_included_files)
@old_swiftlint_yaml_manager.update('included', total_old_included_files) @old_swiftlint_yaml_manager.update('included', total_old_included_files)
is_exist_total_touchin_included_files = (not total_touchin_included_files.nilOrEmpty?) is_exist_total_touchin_included_files = (not total_touchin_included_files.nilOrEmpty?)
is_exist_total_old_included_files = (not total_old_included_files.nilOrEmpty?) is_exist_total_old_included_files = (not total_old_included_files.nilOrEmpty?)
if is_exist_total_touchin_included_files and is_exist_total_old_included_files if is_exist_total_touchin_included_files and is_exist_total_old_included_files
run_multiple_strategy(@touchin_swiftlint_yaml_temporary_path, @old_swiftlint_yaml_temporary_path) run_multiple_strategy(@touchin_swiftlint_yaml_temporary_path, @old_swiftlint_yaml_temporary_path)
elsif is_exist_total_touchin_included_files and not is_exist_total_old_included_files elsif is_exist_total_touchin_included_files and not is_exist_total_old_included_files
@ -75,11 +76,11 @@ class StrategyMaker
puts 'Git did not found swift files to check' puts 'Git did not found swift files to check'
end end
end end
def run_fully_single_strategy def run_fully_single_strategy
run_single_strategy(@touchin_swiftlint_yaml_path) run_single_strategy(@touchin_swiftlint_yaml_path)
end end
def run_simplified_single_strategy(source_root_path) def run_simplified_single_strategy(source_root_path)
included_files = GitСaretaker.get_modified_files included_files = GitСaretaker.get_modified_files
@ -87,34 +88,34 @@ class StrategyMaker
puts 'Git did not found swift files to check' puts 'Git did not found swift files to check'
return return
end end
create_copy_temporary_touchin_files create_copy_temporary_touchin_files
touchin_swiftlint_yaml_manager = YamlManager.new(@touchin_swiftlint_yaml_temporary_path) touchin_swiftlint_yaml_manager = YamlManager.new(@touchin_swiftlint_yaml_temporary_path)
touchin_excluded_files = touchin_swiftlint_yaml_manager.get_configuration('excluded') touchin_excluded_files = touchin_swiftlint_yaml_manager.get_configuration('excluded')
swift_files = SwiftFileManager.new(touchin_excluded_files, '') swift_files = SwiftFileManager.new(touchin_excluded_files, '')
included_files = included_files.select { |file_name| not swift_files.is_excluded_file(file_name) } included_files = included_files.select { |file_name| not swift_files.is_excluded_file(file_name) }
included_files = included_files.map { |file_path| source_root_path + file_path } included_files = included_files.map { |file_path| source_root_path + file_path }
touchin_swiftlint_yaml_manager.update('excluded', []) touchin_swiftlint_yaml_manager.update('excluded', [])
touchin_swiftlint_yaml_manager.update('included', included_files) touchin_swiftlint_yaml_manager.update('included', included_files)
if not included_files.nilOrEmpty? if not included_files.nilOrEmpty?
run_single_strategy(@touchin_swiftlint_yaml_temporary_path) run_single_strategy(@touchin_swiftlint_yaml_temporary_path)
else else
puts 'Git found the swift files to check, but they are excluded in yaml' puts 'Git found the swift files to check, but they are excluded in yaml'
end end
end end
private private
def run_single_strategy(swiftlint_yaml_path) def run_single_strategy(swiftlint_yaml_path)
result_swiftlint_command = get_swiftlint_command(swiftlint_yaml_path) result_swiftlint_command = get_swiftlint_command(swiftlint_yaml_path)
puts result_swiftlint_command puts result_swiftlint_command
run_bash_command(result_swiftlint_command) run_bash_command(result_swiftlint_command)
end end
def run_multiple_strategy(touchin_swiftlint_yaml_temporary_path, old_swiftlint_yaml_temporary_path) def run_multiple_strategy(touchin_swiftlint_yaml_temporary_path, old_swiftlint_yaml_temporary_path)
touchin_swiftlint_command = get_swiftlint_command(touchin_swiftlint_yaml_temporary_path) touchin_swiftlint_command = get_swiftlint_command(touchin_swiftlint_yaml_temporary_path)
old_swiftlint_command = get_swiftlint_command(old_swiftlint_yaml_temporary_path) old_swiftlint_command = get_swiftlint_command(old_swiftlint_yaml_temporary_path)
@ -122,34 +123,34 @@ class StrategyMaker
puts result_swiftlint_command puts result_swiftlint_command
run_bash_command(result_swiftlint_command) run_bash_command(result_swiftlint_command)
end end
def get_swiftlint_command(swiftlint_yaml_path) def get_swiftlint_command(swiftlint_yaml_path)
autocorrect_command = @swiftlint_autocorrect_command + swiftlint_yaml_path autocorrect_command = @swiftlint_autocorrect_command + swiftlint_yaml_path
lint_command = @swiftlint_lint_command + swiftlint_yaml_path lint_command = @swiftlint_lint_command + swiftlint_yaml_path
return autocorrect_command + ' && ' + lint_command return autocorrect_command + ' && ' + lint_command
end end
def run_bash_command(bash_command) def run_bash_command(bash_command)
exit (exec bash_command) exit (exec bash_command)
end end
def create_yaml_managers_and_copy_temporary_files def create_yaml_managers_and_copy_temporary_files
create_copy_temporary_files create_copy_temporary_files
@touchin_swiftlint_yaml_manager = YamlManager.new(@touchin_swiftlint_yaml_temporary_path) @touchin_swiftlint_yaml_manager = YamlManager.new(@touchin_swiftlint_yaml_temporary_path)
@old_swiftlint_yaml_manager = YamlManager.new(@old_swiftlint_yaml_temporary_path) @old_swiftlint_yaml_manager = YamlManager.new(@old_swiftlint_yaml_temporary_path)
end end
def create_copy_temporary_files def create_copy_temporary_files
create_copy_temporary_touchin_files create_copy_temporary_touchin_files
FileUtils.cp @old_swiftlint_yaml_path, @old_swiftlint_yaml_temporary_path FileUtils.cp @old_swiftlint_yaml_path, @old_swiftlint_yaml_temporary_path
end end
def create_copy_temporary_touchin_files def create_copy_temporary_touchin_files
Dir.mkdir(@temporary_swiftlint_folder_name) unless Dir.exist?(@temporary_swiftlint_folder_name) Dir.mkdir(@temporary_swiftlint_folder_name) unless Dir.exist?(@temporary_swiftlint_folder_name)
FileUtils.cp @touchin_swiftlint_yaml_path, @touchin_swiftlint_yaml_temporary_path FileUtils.cp @touchin_swiftlint_yaml_path, @touchin_swiftlint_yaml_temporary_path
end end
def unique_exclude_files(touchin_swiftlint_yaml_manager, old_swiftlint_yaml_manager) def unique_exclude_files(touchin_swiftlint_yaml_manager, old_swiftlint_yaml_manager)
touchin_excluded_files = touchin_swiftlint_yaml_manager.get_configuration('excluded') touchin_excluded_files = touchin_swiftlint_yaml_manager.get_configuration('excluded')
old_excluded_files = old_swiftlint_yaml_manager.get_configuration('excluded') old_excluded_files = old_swiftlint_yaml_manager.get_configuration('excluded')

View File

@ -3,7 +3,10 @@ require_relative 'setting_option.rb'
require_relative 'strategy_maker.rb' require_relative 'strategy_maker.rb'
setting = SettingOption.new setting = SettingOption.new
strategy_maker = StrategyMaker.new(setting.project_root_path, setting.swiftlint_executable_path, setting.touchin_swiftlint_yaml_path) strategy_maker = StrategyMaker.new(setting.project_root_path,
setting.swiftlint_executable_path,
setting.touchin_swiftlint_yaml_path,
setting.old_swiftlint_yaml_path)
if setting.check_mode.eql? 'fully' and setting.use_multiple.true? if setting.check_mode.eql? 'fully' and setting.use_multiple.true?
strategy_maker.run_fully_multiple_strategy(setting.source_date) strategy_maker.run_fully_multiple_strategy(setting.source_date)

100
xcode/build_phases/swiftlint.sh Normal file → Executable file
View File

@ -1,2 +1,98 @@
SOURCES_DIR=${1:-${TARGET_NAME}} # first argument or TARGET_NAME #!/bin/sh
${PODS_ROOT}/SwiftLint/swiftlint autocorrect --path ${SOURCES_DIR} --config ${PROJECT_DIR}/build-scripts/xcode/.swiftlint.yml && ${PODS_ROOT}/SwiftLint/swiftlint --path ${SOURCES_DIR} --config ${PROJECT_DIR}/build-scripts/xcode/.swiftlint.yml
# Description:
# Runs swiftlint with selected or default config file.
# By default it runs only for modified files.
#
# Parameters:
# $1 - path to swiftlint executable.
# $2 - path to swiftlint config.
#
# Required environment variables:
# SCRIPT_DIR - directory of current script.
# SRCROOT - project directory.
#
# Optional environment variables:
# SWIFTLINT_EXECUTABLE - path to swiftlint executable.
# SWIFTLINT_CONFIG_PATH - path to swiftlint config.
# PODS_ROOT - cocoapods installation directory (eg. ${SRCROOT}/Pods) if SWIFTLINT_EXECUTABLE or ${1} is missing
# SCRIPT_INPUT_FILE_COUNT - number of files listed in "Input files" of build phase.
# SCRIPT_INPUT_FILE_{N} - file path to directory that should be checked.
# FORCE_LINT - don't exclude not modified files.
# AUTOCORRECT - format and fix code before lint.
#
# Example of usage:
# swiftlint.sh
# FORCE_LINT=true; swiftlint.sh
# swiftlint.sh Pods/Swiftlint/swiftlint build-scripts/xcode/.swiftlint.yml
#
readonly SOURCES_DIRS=`. ${SCRIPT_DIR}/common/read_input_file_names.sh "\n" ${SRCROOT}`
if [ -z "${SWIFTLINT_EXECUTABLE}" ]; then
if [ ! -z "${1}" ]; then
readonly SWIFTLINT_EXECUTABLE=${1}
elif [ ! -z "${PODS_ROOT}" ]; then
readonly SWIFTLINT_EXECUTABLE=${PODS_ROOT}/SwiftLint/swiftlint
else
readonly SWIFTLINT_EXECUTABLE=${SRCROOT}/Pods/SwiftLint/swiftlint
fi
fi
if [ -z "${SWIFTLINT_CONFIG_PATH}" ]; then
if [ ! -z "${2}" ]; then
readonly SWIFTLINT_CONFIG_PATH=${2}
else
readonly SWIFTLINT_CONFIG_PATH=${SCRIPT_DIR}/../.swiftlint.yml
fi
fi
if [ ! -z "${FORCE_LINT}" ]; then
# Если задана переменная FORCE_LINT, то проверяем все файлы проекта
for SOURCE_DIR in ${SOURCES_DIRS}; do
if [ ! -z "${AUTOCORRECT}" ]; then
${SWIFTLINT_EXECUTABLE} lint --config ${SWIFTLINT_CONFIG_PATH} --fix --format "${SRCROOT}/${SOURCE_DIR}"
fi
${SWIFTLINT_EXECUTABLE} lint --config ${SWIFTLINT_CONFIG_PATH} "${SRCROOT}/${SOURCE_DIR}"
done
else
# Xcode упадет, если будем использовать большое количество Script Input Files,
# так как просто переполнится стек - https://unix.stackexchange.com/questions/357843/setting-a-long-environment-variable-breaks-a-lot-of-commands
# Поэтому воспользуемся "скрытым" параметром Swiflint - https://github.com/realm/SwiftLint/pull/3313
# Создадим временный файл swiftlint_files с префиксом @ и в нем уже определим список файлов
# необходимых для линтовки :)
lint_files_path=`mktemp`
# Проходимся по папкам, которые требуют линтовки
for SOURCE_DIR in ${SOURCES_DIRS}; do
LINE_PREFIX="${SRCROOT}/"
pushd .
cd ${SRCROOT} # in case of runing script outside project folder (SPM)
# Отбираем файлы, которые были изменены или созданы
source_unstaged_files=$(git diff --diff-filter=d --name-only --line-prefix=${LINE_PREFIX} ${SOURCE_DIR} | grep "\.swift$")
source_staged_files=$(git diff --diff-filter=d --name-only --line-prefix=${LINE_PREFIX} --cached ${SOURCE_DIR} | grep "\.swift$")
popd
if [ ! -z "${source_unstaged_files}" ]; then
echo "${source_unstaged_files}" >> ${lint_files_path}
fi
if [ ! -z "${source_staged_files}" ]; then
echo "${source_staged_files}" >> ${lint_files_path}
fi
done
swiftlint_files_path="@${lint_files_path}"
if [ ! -z "${AUTOCORRECT}" ]; then
${SWIFTLINT_EXECUTABLE} lint --config ${SWIFTLINT_CONFIG_PATH} --fix --format --force-exclude --use-alternative-excluding ${swiftlint_files_path}
fi
${SWIFTLINT_EXECUTABLE} lint --config ${SWIFTLINT_CONFIG_PATH} --force-exclude --use-alternative-excluding ${swiftlint_files_path}
fi

View File

@ -1,4 +1,5 @@
arguments=("$@") readonly ARGUMENTS=("$@")
ignored_files=$(IFS=, ; echo "${arguments[*]}") readonly IGNORED_FILES=$(IFS=, ; echo "${ARGUMENTS[*]}")
readonly SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
ruby ${PROJECT_DIR}/build-scripts/xcode/build_phases/Unused.rb --config ${PROJECT_DIR}/build-scripts/xcode/UnusedConfig.yml --exclude ${ignored_files} ruby ${SCRIPT_DIR}/Unused.rb --config ${SCRIPT_DIR}/../UnusedConfig.yml --exclude ${IGNORED_FILES}

View File

@ -0,0 +1,8 @@
readonly SOURCES_DIR=${1:-${PROJECT_DIR}/${PRODUCT_NAME}} # first argument set product dir
readonly UNUSED_RESOURCES_SCRIPT=${2:-${PROJECT_DIR}/build-scripts/xcode/build_phases/common/unused_resources} # second argument set script path
readonly REPORTS_DIR=${PROJECT_DIR}/code-quality-reports
readonly FILES_TO_EXCLUDE=`find ${SOURCES_DIR} -type d -name Localization -or -name Generated | paste -sd " " -`
mkdir ${REPORTS_DIR}
${UNUSED_RESOURCES_SCRIPT} --project ${SOURCES_DIR} --exclude ${FILES_TO_EXCLUDE} --action "l" > ${REPORTS_DIR}/Unused_resources_log.txt

View File

@ -2,6 +2,7 @@ $appName = File.basename(Dir['../*.xcworkspace'].first, '.*')
require_relative 'fastlane/touchlane/lib/touchlane' require_relative 'fastlane/touchlane/lib/touchlane'
private_lane :installDependencies do |options| private_lane :installDependencies do |options|
podsReposPath = File.expand_path "~/.cocoapods/repos/master/" podsReposPath = File.expand_path "~/.cocoapods/repos/master/"
lockFilePath = "#{podsReposPath}/.git/index.lock" lockFilePath = "#{podsReposPath}/.git/index.lock"
@ -11,49 +12,15 @@ private_lane :installDependencies do |options|
sh("rm -rf #{podsReposPath}") sh("rm -rf #{podsReposPath}")
end end
if File.exists? "../Gemfile"
bundle_install(path: "../.gem")
end
cocoapods( cocoapods(
repo_update: true try_repo_update_on_error: true
) )
if File.exists? "../Cartfile"
use_rome = File.exists? "../Romefile"
swift_version = sh("xcrun swift --version | head -1 | sed 's/.*\\(\(.*\)\\).*/\\1/' | tr -d \"()\" | tr \" \" \"-\"").chop
rome_path = "Pods/Rome/rome"
rome_options = "--platform iOS --cache-prefix #{swift_version} --romefile Romefile"
carthage_install = lambda do
if use_rome
sh("cd .. && #{rome_path} download #{rome_options}")
end
carthage(command: "bootstrap", platform: "iOS", cache_builds: true)
if use_rome
sh("cd .. && #{rome_path} list --missing #{rome_options} | awk '{print $1}' | xargs -I framework_name #{rome_path} upload framework_name #{rome_options}")
end
end
begin
carthage_install.call
rescue
# workaround for https://github.com/Carthage/Carthage/issues/2298
sh("rm -rf ~/Library/Caches/org.carthage.CarthageKit")
carthage_install.call
end
end
end end
private_lane :uploadToFirebase do |options| private_lane :uploadToFirebase do |options|
releaseNotesFile = "release-notes.txt" releaseNotesFile = "release-notes.txt"
sh("touch ../#{releaseNotesFile}") sh("touch ../#{releaseNotesFile}")
sh("yarn install")
app_target_folder_name = options[:appName] || $appName app_target_folder_name = options[:appName] || $appName
configuration_type = Touchlane::ConfigurationType.from_type(options[:type]) configuration_type = Touchlane::ConfigurationType.from_type(options[:type])
@ -61,33 +28,48 @@ private_lane :uploadToFirebase do |options|
google_app_id = get_info_plist_value(path: gsp_plist_path, key: "GOOGLE_APP_ID") google_app_id = get_info_plist_value(path: gsp_plist_path, key: "GOOGLE_APP_ID")
firebase_app_distribution( firebase_app_distibution_groups_path = File.expand_path "../firebase_app_distribution_groups"
# Select groups_file or groups parameter depending on groups file existence
if File.exists? firebase_app_distibution_groups_path
firebase_app_distribution(
app: google_app_id,
ipa_path: options[:ipa_path],
groups_file: firebase_app_distibution_groups_path,
release_notes_file: releaseNotesFile
)
else
firebase_app_distribution(
app: google_app_id, app: google_app_id,
ipa_path: options[:ipa_path], ipa_path: options[:ipa_path],
groups: "touch-instinct", groups: "touch-instinct",
release_notes_file: releaseNotesFile, release_notes_file: releaseNotesFile
firebase_cli_path: File.expand_path("../node_modules/firebase-tools/lib/bin/firebase.js") )
) end
upload_symbols_to_crashlytics(
gsp_path: get_google_services_plist_path(app_target_folder_name, configuration_type)
)
end end
private_lane :uploadToAppStore do |options| def upload_to_app_store_using_options(options, submit_for_review = false)
upload_to_app_store( upload_to_app_store(
username: options[:username] || options[:apple_id], username: options[:username] || options[:apple_id],
api_key_path: options[:api_key_path],
api_key: options[:api_key],
ipa: options[:ipa_path], ipa: options[:ipa_path],
build_number: options[:ipa_path].nil? ? options[:buildNumber] : nil,
skip_binary_upload: options[:ipa_path].nil?,
skip_screenshots: true,
force: true, # skip metainfo prompt force: true, # skip metainfo prompt
submit_for_review: submit_for_review,
submission_information: options[:submission_information],
skip_metadata: true, skip_metadata: true,
team_id: options[:itc_team_id], team_id: options[:itc_team_id],
dev_portal_team_id: options[:team_id] dev_portal_team_id: options[:team_id],
precheck_include_in_app_purchases: false
) )
end end
private_lane :addShield do |options| private_lane :addShield do |options|
buildNumber = options[:buildNumber] buildNumber = options[:buildNumber]
buildDescription = options[:xcconfig_name] # EnterpriseCustomerDev1WithoutSSLPinningRelease buildDescription = options[:lane_name] # EnterpriseCustomerDev1WithoutSSLPinningRelease
.split(/(?=[A-Z])/) # -> ["Enterprise", "Customer", "Dev1", "Without", "S", "S", "L", "Pinning", "Release"] .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"] .map { |v| v.gsub(/[[:lower:]]+/, "") }[1..2] # -> ["E", "C", "D1", "W", "S", "S", "L", "P", "R"] -> ["C", "D1"]
.join # -> "CD1" .join # -> "CD1"
@ -103,148 +85,139 @@ private_lane :addShield do |options|
end end
private_lane :buildConfiguration do |options| private_lane :buildConfiguration do |options|
appName = options[:appName] || $appName options[:appName] = options[:appName] || $appName
lane_name = lane_context[SharedValues::LANE_NAME] lane_name = options[:lane_name] || lane_context[SharedValues::LANE_NAME]
options[:scheme] = appName options[:scheme] = options[:scheme] || options[:appName]
options[:xcconfig_name] = lane_name options[:lane_name] = lane_name
ipa_name = "#{options[:appName]}.ipa"
options[:output_name] = ipa_name
options[:ipa_path] = "./#{ipa_name}"
options[:dsym_path] = "./#{options[:appName]}.app.dSYM.zip"
options[:xcodeproj_path] = options[:xcodeproj_path] || "../#{options[:appName]}.xcodeproj"
options[:workspace] = options[:workspace] || File.expand_path("../#{options[:appName]}.xcworkspace")
configuration_type = Touchlane::ConfigurationType.from_lane_name(lane_name) configuration_type = Touchlane::ConfigurationType.from_lane_name(lane_name)
options = fill_up_options_using_configuration_type(options, configuration_type) options = fill_up_options_using_configuration_type(options, configuration_type, true)
generate_xcodeproj_if_needed(options)
openKeychain(options) openKeychain(options)
if is_ci if !options[:buildNumber].nil?
increment_build_number( increment_build_number(
build_number: options[:buildNumber] build_number: options[:buildNumber]
) )
end end
ipa_name = "#{appName}.ipa"
options[:output_name] = ipa_name
options[:ipa_path] = "./#{ipa_name}"
options[:dsym_path] = "./#{appName}.app.dSYM.zip"
options[:xcodeproj_path] = "../#{appName}.xcodeproj"
options[:workspace] = "./#{appName}.xcworkspace"
installDependencies(options) installDependencies(options)
run_code_generation_phase_if_needed(options)
if !(options[:uploadToFabric] || options[:uploadToAppStore]) if !(options[:uploadToFabric] || options[:uploadToAppStore])
options[:skip_package_ipa] = true options[:skip_package_ipa] = true
sync_code_signing_using_options(options) install_signing_identities(options)
buildArchive(options) # check build failures and static analysis buildArchive(options) # check build failures and static analysis
end end
if options[:uploadToFabric] if options[:uploadToFabric]
sync_code_signing_using_options(options) install_signing_identities(options)
addShield(options) addShield(options)
buildArchive(options) buildArchive(options)
uploadToFirebase(options) uploadToFirebase(options)
end end
if options[:uploadToAppStore] if options[:uploadToAppStore]
options[:compileBitcode] = options[:compileBitcode].nil? ? true : options[:compileBitcode]
options[:include_symbols] = options[:include_symbols].nil? ? true : options[:include_symbols] options[:include_symbols] = options[:include_symbols].nil? ? true : options[:include_symbols]
sync_code_signing_using_options(options) install_signing_identities(options)
buildArchive(options) buildArchive(options)
uploadToAppStore(options) upload_to_app_store_using_options(options, false)
end end
upload_symbols_to_crashlytics(
gsp_path: get_google_services_plist_path(options[:appName], configuration_type)
)
end end
private_lane :buildArchive do |options| private_lane :buildArchive do |options|
require 'json'
icloudEnvironment = options[:iCloudContainerEnvironment] || "" icloudEnvironment = options[:iCloudContainerEnvironment] || ""
exportOptions = icloudEnvironment.to_s.empty? ? {} : {iCloudContainerEnvironment: icloudEnvironment} exportOptions = icloudEnvironment.to_s.empty? ? {} : {iCloudContainerEnvironment: icloudEnvironment}
exportOptions[:compileBitcode] = options[:compileBitcode] || false
xcconfig_name = options[:xcconfig_name] lane_name = options[:lane_name]
configuration = options[:configuration] configuration = options[:configuration]
xcodeproj_path = options[:xcodeproj_path] xcodeproj_path = options[:xcodeproj_path]
xcodes(select_for_current_build_only: true)
if configuration != "AppStore" # AppStore uses xcconfig choosen in Xcode if configuration != "AppStore" # AppStore uses xcconfig choosen in Xcode
set_xcconfig_for_configuration_of_project(xcconfig_name, configuration, xcodeproj_path) set_xcconfig_for_configuration_of_project(lane_name, configuration, xcodeproj_path)
end end
gym( gym(
clean: true, clean: true,
workspace: options[:workspace], workspace: options[:workspace],
scheme: options[:scheme], scheme: options[:scheme],
archive_path: "./", archive_path: "./#{$appName}.xcarchive",
output_directory: "./", buildlog_path: "./",
output_name: options[:output_name], output_name: options[:output_name],
configuration: configuration, configuration: configuration,
export_method: options[:export_method], export_method: options[:export_method],
export_options: exportOptions, export_options: exportOptions,
skip_package_ipa: options[:skip_package_ipa], skip_package_ipa: options[:skip_package_ipa],
include_symbols: options[:include_symbols] || false, include_symbols: options[:include_symbols] || false
include_bitcode: options[:compileBitcode] || false,
) )
end end
lane :CreatePushCertificate do |options| lane :SubmitForReview do |options|
configuration = get_configuration_for_type(options[:type] || "development") configuration_type = Touchlane::ConfigurationType.from_type("appstore")
options = configuration.to_options.merge(options) options = fill_up_options_using_configuration_type(options, configuration_type, false)
certificates_path = File.expand_path "../Certificates" upload_to_app_store_using_options(options, true)
Dir.mkdir(certificates_path) unless File.directory?(certificates_path)
app_identifier = options[:app_identifier]
get_push_certificate(
development: options[:development].nil? ? true : options[:development],
generate_p12: true,
active_days_limit: 30, # create new certificate if old one will expire in 30 days
save_private_key: false,
app_identifier: (app_identifier.is_a? Array) ? app_identifier.first : app_identifier,
username: options[:username] || options[:apple_id],
team_id: options[:team_id],
p12_password: "123", # empty password won't work with Pusher
output_path: certificates_path
)
end end
lane :SyncCodeSigning do |options| lane :InstallDevelopmentSigningIdentities do |options|
configuration_type = Touchlane::ConfigurationType.from_type(options[:type]) configuration_type = Touchlane::ConfigurationType.from_type("development")
options = fill_up_options_using_configuration_type(options, configuration_type) options = fill_up_options_using_configuration_type(options, configuration_type)
sync_code_signing_using_options(options) install_signing_identities(options)
end end
lane :SyncSymbols do |options| lane :RefreshProfiles do |options|
configuration = get_configuration_for_type(options[:type]) type = options[:type] || "development"
options = configuration.to_options.merge(options)
appName = options[:appName] || $appName configuration_type = Touchlane::ConfigurationType.from_type(type)
options = fill_up_options_using_configuration_type(options, configuration_type)
xcodeproj_path = File.expand_path "../#{appName}.xcodeproj" refresh_profiles(options)
end
version_number = options[:version] || get_version_number(xcodeproj: xcodeproj_path, target: appName) lane :ReplaceDevelopmentCertificate do |options|
build_number = options[:build_number] || get_build_number(xcodeproj: xcodeproj_path) configuration_type = Touchlane::ConfigurationType.from_type("development")
options = fill_up_options_using_configuration_type(options, configuration_type, true)
if configuration.type.is_app_store replace_development_certificate(options)
download_dsyms( end
username: options[:username],
app_identifier: options[:app_identifier].first,
team_id: options[:itc_team_id],
version: version_number,
build_number: build_number
)
end
app_target_folder_name = appName lane :SyncAppStoreIdentities do |options|
configuration_type = Touchlane::ConfigurationType.from_type("appstore")
options = fill_up_options_using_configuration_type(options, configuration_type, true)
upload_symbols_to_crashlytics( options[:readonly] = false
gsp_path: get_google_services_plist_path(app_target_folder_name, configuration.type) sync_signing_identities(options)
) end
clean_build_artifacts lane :ManuallyUpdateCodeSigning do |options|
manually_update_code_signing(get_default_options.merge(options))
end end
private_lane :openKeychain do |options| private_lane :openKeychain do |options|
@ -258,7 +231,7 @@ private_lane :openKeychain do |options|
name: options[:keychain_name], name: options[:keychain_name],
password: options[:keychain_password], password: options[:keychain_password],
unlock: true, unlock: true,
timeout: false, timeout: 0,
add_to_search_list: !keychain_exists add_to_search_list: !keychain_exists
) )
else else
@ -269,111 +242,78 @@ private_lane :openKeychain do |options|
end end
end end
lane :ManuallyUpdateCodeSigning do |options| def get_default_options
# based on this article https://medium.com/@jonathancardoso/using-fastlane-match-with-existing-certificates-without-revoking-them-a325be69dac6 {
require 'fastlane_core' :git_url => get_signing_identities_path(),
require 'match' :signing_identities_path => get_signing_identities_path(),
:storage_mode => Touchlane::LocalStorage::STORAGE_TYPE
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 end
def sync_code_signing_using_options(options) def get_signing_identities_path
match( File.expand_path "../EncryptedSigningIdentities"
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 end
def fill_up_options_using_configuration_type(options, configuration_type) def fill_up_options_using_configuration_type(options, configuration_type, keychain_password_required = false)
configuration = get_configuration_for_type(configuration_type.type) configuration = get_configuration_for_type(configuration_type.type)
configuration.to_options api_key_path = File.expand_path "../fastlane/#{configuration_type.prefix}_api_key.json"
.merge(get_keychain_options(options)) is_api_key_file_exists = File.exists?(api_key_path)
# default_options required to be empty due to the possibility of skipping the configuration type check below
default_options = get_default_options
# Check whether configuration type is required to configure one of api key parameters or not
if configuration_type.is_app_store || configuration_type.is_development
# Check whether API key JSON file exists or not
if is_api_key_file_exists
# If exists then fill in all required information through api_key_path parameter
# and set a value to an options` parameter respectively
default_options[:api_key_path] = api_key_path
else
# If doesn't exist then build api_key parameter through app_store_connect_api_key action
# and set a value to an options` parameter respectively also
default_options[:api_key] = get_app_store_connect_api_key()
end
end
default_options
.merge(configuration.to_options)
.merge(get_keychain_options(options, keychain_password_required))
.merge(options) .merge(options)
end end
def get_keychain_options(options) def get_app_store_connect_api_key()
require 'json'
api_key_parameters = JSON.parse(ENV['API_KEY_JSON'])
return app_store_connect_api_key(
key_id: api_key_parameters['key_id'],
issuer_id: api_key_parameters['issuer_id'],
key_content: api_key_parameters['key'],
duration: api_key_parameters['duration'],
in_house: api_key_parameters['in_house']
)
end
def get_keychain_options(options, keychain_password_required = false)
keychain_name = options[:keychain_name] keychain_name = options[:keychain_name]
keychain_password = options[:keychain_password] keychain_password = options[:keychain_password]
if is_ci? if is_ci?
keychain_name = keychain_name || "ci.keychain" keychain_name = keychain_name || "ci.keychain"
keychain_password = keychain_password || "" keychain_password = keychain_password || ""
else elsif keychain_password_required && keychain_password.nil?
keychain_password = keychain_password || prompt( keychain_password = prompt(
text: "Please enter your keychain password (account password): ", text: "Please enter your keychain password (account password): ",
secure_text: true secure_text: true
) )
@ -389,10 +329,10 @@ def get_configuration_for_type(type)
end end
def get_google_services_plist_path(app_target_folder_name, configuration_type) def get_google_services_plist_path(app_target_folder_name, configuration_type)
File.expand_path "../#{app_target_folder_name}/Resources/#{configuration_type.prefix}-GoogleService-Info.plist" File.expand_path "../#{app_target_folder_name}/Resources/GoogleService-Info.plist"
end end
def set_xcconfig_for_configuration_of_project(xcconfig_name, configuration, xcodeproj_path) def set_xcconfig_for_configuration_of_project(lane_name, configuration, xcodeproj_path)
require 'xcodeproj' require 'xcodeproj'
project = Xcodeproj::Project.open(xcodeproj_path) project = Xcodeproj::Project.open(xcodeproj_path)
@ -400,7 +340,8 @@ def set_xcconfig_for_configuration_of_project(xcconfig_name, configuration, xcod
target_to_modify_selector = lambda do |t| target_to_modify_selector = lambda do |t|
supported_product_types = [ supported_product_types = [
Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application], Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application],
Xcodeproj::Constants::PRODUCT_TYPE_UTI[:app_extension] Xcodeproj::Constants::PRODUCT_TYPE_UTI[:app_extension],
Xcodeproj::Constants::PRODUCT_TYPE_UTI[:framework]
] ]
return !t.test_target_type? && supported_product_types.include?(t.product_type) return !t.test_target_type? && supported_product_types.include?(t.product_type)
end end
@ -408,12 +349,35 @@ def set_xcconfig_for_configuration_of_project(xcconfig_name, configuration, xcod
application_targets = project.native_targets.select(&target_to_modify_selector) application_targets = project.native_targets.select(&target_to_modify_selector)
application_targets.each do |target| application_targets.each do |target|
build_configuration = target.build_configuration_list[configuration] config_name = target.name + lane_name
config_name = target.name + xcconfig_name
build_configuration_reference = project.files.select { |f| f.path.start_with?(config_name) }.first build_configuration_reference = project.files.select { |f| f.path.start_with?(config_name) }.first
build_configuration.base_configuration_reference = build_configuration_reference
if !build_configuration_reference.nil? # target has custom xcconfig
build_configuration = target.build_configuration_list[configuration]
build_configuration.base_configuration_reference = build_configuration_reference
end
end end
project.save() project.save()
end end
def generate_xcodeproj_if_needed(options)
project_yml_path = File.expand_path "../project.yml"
if !File.exists?(options[:xcodeproj_path]) && File.exists?(project_yml_path)
xcodegen(
spec: project_yml_path
)
end
end
# Build phases
def run_code_generation_phase_if_needed(options)
code_generation_script_path = File.expand_path "../.githooks/scripts/CodeGen.sh"
if File.exists? code_generation_script_path
sh(code_generation_script_path, options[:workspace])
end
end

@ -1 +1 @@
Subproject commit 3f81529c1425a74f43fe84fe8befffd81a442cc7 Subproject commit a8f072f216684bd7f5563c0211f71d6637a5f92d

View File

@ -0,0 +1,132 @@
require 'json'
require 'mustache'
require 'yaml'
require_relative '../fastlane/touchlane/lib/touchlane/configuration_type'
class String
def in_current_dir
"#{__dir__}/#{self}"
end
end
class ConfigRenderer
class XCConfigKeys
DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM"
PRODUCT_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER"
CODE_SIGN_STYLE = "CODE_SIGN_STYLE"
end
INHERITED_PREFIX = "$(inherited)"
private_constant :INHERITED_PREFIX
def initialize(configurations_file_path, build_parameters_path, configs_folder_name)
@configurations_file_path = configurations_file_path
@build_parameters_path = build_parameters_path
@configs_folder_name = configs_folder_name
end
def render_xconfigs
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
# 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 #{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"]
targets = $configurations["targets"]
# 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(temp_configs_data_file_path))
# Run through all configs
configs.each do |config|
# Take default values
distribution_type = Touchlane::ConfigurationType.from_account_type(config["account_type"]).type
properties = target[distribution_type]
# Add properties from settings file
properties.each do |key, value|
if config["xcconfig_options"].any? { |option| key == option["key"] }
config["xcconfig_options"].map! { |option| key == option["key"] ? merge_config_data(key, option["value"], value) : option }
else
config["xcconfig_options"].append(config_option(key, value))
end
end
# Add missing properties if needed
config["xcconfig_options"].concat(generate_missing_properties(target_name, properties, distribution_type))
# Create settings pack
config_data = {
"target_name": target_name,
"abstract_targets_prefix": target["abstract_targets_prefix"],
"configuration": config
}
# 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))
}
end
end
# Remove config file, it's trash
File.delete(temp_configs_data_file_path) if File.exist?(temp_configs_data_file_path)
end
# Make tuple of key and value become mustache template element
def config_option(key, value)
return { "key" => key, "value" => value }
end
def merge_config_data(key, config_value, settings_value)
if settings_value.start_with?(INHERITED_PREFIX)
new_value = settings_value.split(INHERITED_PREFIX).last
return config_option(key, config_value + new_value)
else
return config_option(key, settings_value)
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
# Generate missing properties if needed
def generate_missing_properties(target_name, properties, distribution_type)
result = []
# Bundle_id_key should be among the properties (required by fastlane)
unless properties.key?(XCConfigKeys::PRODUCT_BUNDLE_IDENTIFIER)
raise "#{target_name}: Could not find #{XCConfigKeys::PRODUCT_BUNDLE_IDENTIFIER} for #{distribution_type}"
end
unless properties.key?(XCConfigKeys::DEVELOPMENT_TEAM)
result.append(fetch_development_team(XCConfigKeys::DEVELOPMENT_TEAM, distribution_type))
end
unless properties.key?(XCConfigKeys::CODE_SIGN_STYLE)
result.append(config_option(XCConfigKeys::CODE_SIGN_STYLE, "Manual"))
end
return result
end
end

View File

@ -1,13 +1,16 @@
targets: targets:
TestProject: TestProject:
abstract_targets_prefix: "-TestProjectKit"
development: development:
PRODUCT_BUNDLE_IDENTIFIER: "ru.touchin.testproject" PRODUCT_BUNDLE_IDENTIFIER: "ru.touchin.testproject"
PROVISIONING_PROFILE_SPECIFIER: "TestProjectDev" PROVISIONING_PROFILE_SPECIFIER: "TestProjectDev"
CODE_SIGN_ENTITLEMENTS: "TestProject/Standard.entitlements" CODE_SIGN_ENTITLEMENTS: "TestProject/Standard.entitlements"
SWIFT_ACTIVE_COMPILATION_CONDITIONS: "$(inherited) DEBUG_MENU"
enterprise: enterprise:
PRODUCT_BUNDLE_IDENTIFIER: "com.touchin.testproject" PRODUCT_BUNDLE_IDENTIFIER: "com.touchin.testproject"
PROVISIONING_PROFILE_SPECIFIER: "TestProjectEnterprise" PROVISIONING_PROFILE_SPECIFIER: "TestProjectEnterprise"
CODE_SIGN_ENTITLEMENTS: "TestProject/Enterprise.entitlements" CODE_SIGN_ENTITLEMENTS: "TestProject/Enterprise.entitlements"
SWIFT_ACTIVE_COMPILATION_CONDITIONS: "$(inherited) DEBUG_MENU"
appstore: appstore:
PRODUCT_BUNDLE_IDENTIFIER: "ru.customer.domain" PRODUCT_BUNDLE_IDENTIFIER: "ru.customer.domain"
PROVISIONING_PROFILE_SPECIFIER: "TestProjectAppStore" PROVISIONING_PROFILE_SPECIFIER: "TestProjectAppStore"
@ -15,13 +18,13 @@ targets:
types: types:
development: development:
apple_id: "apple@touchin.ru" apple_id: "iosdev@touchin.ru"
team_id: "**********" team_id: "**********"
itc_team_id: "**********" itc_team_id: "**********"
enterprise: enterprise:
apple_id: "enterpriseapple@touchin.ru" apple_id: "enterpriseapple@touchin.ru"
team_id: "**********" team_id: "**********"
appstore: appstore:
apple_id: "apple@touchin.ru" apple_id: "iosdev@touchin.ru"
team_id: "**********" team_id: "**********"
itc_team_id: "**********" itc_team_id: "**********"

View File

@ -1,7 +1,4 @@
require 'json' require_relative "config_renderer"
require 'mustache'
require 'yaml'
# #
# Usage: render_xcconfigs.rb <configurations.yaml> <build_parameters.yaml> [<ouptut folder>] # Usage: render_xcconfigs.rb <configurations.yaml> <build_parameters.yaml> [<ouptut folder>]
# #
@ -10,148 +7,9 @@ require 'yaml'
# It is recommended to remove old .xcconfig files before running this script. # It is recommended to remove old .xcconfig files before running this script.
# #
class String
def in_current_dir
"#{__dir__}/#{self}"
end
end
# Input files paths # Input files paths
configurations_file_path = ARGV[0] 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_path = ARGV[1]
configs_folder_name = ARGV[2] || "TargetConfigurations" configs_folder_name = ARGV[2] || "TargetConfigurations"
# Create config directory if needed ConfigRenderer.new(configurations_file_path, build_parameters_path, configs_folder_name).render_xconfigs()
Dir.mkdir(configs_folder_name) unless Dir.exist?(configs_folder_name)
# 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"]
# Set global property
targets = $configurations["targets"]
# Make tuple of key and value become mustache template element
def config_option(key, value)
return { "key" => key, "value" => value }
end
# 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, 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_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, 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"
# 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(fetch_development_team(development_team_key, distribution_type))
end
unless properties.key?(provisioning_key)
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_name, target|
# 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
configs.each do |config|
# Take default values
distribution_type = distribution_type_of(config["account_type"])
properties = target[distribution_type]
# 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, distribution_type))
# Create settings pack
config_data = {
"target_name": target_name,
"configuration": config
}
# 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))
}
end
end
# Remove config file, it's trash
File.delete(temp_configs_data_file_path) if File.exist?(temp_configs_data_file_path)

View File

@ -1,7 +1,5 @@
#include "Pods/Target Support Files/Pods-{{target_name}}/Pods-{{target_name}}.{{configuration.build_type}}.xcconfig" #include "Pods/Target Support Files/Pods{{abstract_targets_prefix}}-{{target_name}}/Pods{{abstract_targets_prefix}}-{{target_name}}.{{configuration.build_type}}.xcconfig"
{{#configuration.xcconfig_options}} {{#configuration.xcconfig_options}}
{{key}} = {{value}} {{key}} = {{value}}
{{/configuration.xcconfig_options}} {{/configuration.xcconfig_options}}
CODE_SIGN_STYLE = Manual

View File

@ -0,0 +1,86 @@
require 'match'
require 'fileutils'
require 'fastlane_core/ui/ui'
module Touchlane
class LocalStorage < Match::Storage::Interface
attr_accessor :signing_identities_path
STORAGE_TYPE = "local"
def self.configure(params)
return self.new(
# we can't pass signing_identities_path since params is hardcoded in match/runner.rb
signing_identities_path: params[:git_url]
)
end
def initialize(signing_identities_path: nil)
self.signing_identities_path = signing_identities_path
end
def prefixed_working_directory
return working_directory
end
def download
# Check if we already have a functional working_directory
return if @working_directory
# No existing working directory, creating a new one now
self.working_directory = Dir.mktmpdir
Dir.mkdir(self.signing_identities_path) unless File.exists?(self.signing_identities_path)
FileUtils.cp_r("#{self.signing_identities_path}/.", self.working_directory)
end
def human_readable_description
"Local folder [#{self.signing_identities_path}]"
end
def upload_files(files_to_upload: [], custom_message: nil)
# `files_to_upload` is an array of files that need to be moved to signing identities dir
# Those doesn't mean they're new, it might just be they're changed
# Either way, we'll upload them using the same technique
files_to_upload.each do |current_file|
# Go from
# "/var/folders/px/bz2kts9n69g8crgv4jpjh6b40000gn/T/d20181026-96528-1av4gge/profiles/development/Development_me.mobileprovision"
# to
# "profiles/development/Development_me.mobileprovision"
#
# We also have to remove the trailing `/` as Google Cloud doesn't handle it nicely
target_path = current_file.gsub(self.working_directory + "/", "")
absolute_target_path = File.join(self.signing_identities_path, target_path)
FileUtils.mkdir_p(File.dirname(absolute_target_path))
FileUtils.cp_r(current_file, absolute_target_path, remove_destination: true)
end
end
def delete_files(files_to_delete: [], custom_message: nil)
files_to_delete.each do |file_name|
target_path = file_name.gsub(self.working_directory + "/", "")
File.delete(File.join(self.signing_identities_path, target_path))
end
end
def skip_docs
false
end
def list_files(file_name: "", file_ext: "")
Dir[File.join(working_directory, "**", file_name, "*.#{file_ext}")]
end
def generate_matchfile_content
path = Fastlane::UI.input("Path to the signing identities folder: ")
return "git_url(\"#{path}\")"
end
end
end

View File

@ -0,0 +1,16 @@
require 'match'
# ugly hack to add support for custom storage
Match.module_eval do
def self.storage_modes
return ['git', 'google_cloud' 's3', Touchlane::LocalStorage::STORAGE_TYPE]
end
end
def register_local_storage_for_match
storage_type = Touchlane::LocalStorage::STORAGE_TYPE
Match::Storage.register_backend(type: storage_type, storage_class: Touchlane::LocalStorage)
Match::Encryption.register_backend(type: storage_type, encryption_class: Match::Encryption::OpenSSL)
end

View File

@ -1,4 +1,9 @@
module Touchlane module Touchlane
require_relative "configuration_type" require_relative "touchlane/configuration_type"
require_relative "configuration" require_relative "touchlane/configuration"
end require_relative "match/storage/local_storage_register"
require_relative "touchlane/actions/sync_signing_identities"
require_relative "touchlane/actions/refresh_profiles"
require_relative "touchlane/actions/replace_development_certificate"
require_relative "touchlane/actions/manually_update_code_signing"
end

View File

@ -0,0 +1,62 @@
require 'match'
require_relative '../../match/storage/local_storage'
def manually_update_code_signing(options)
register_local_storage_for_match()
storage_factory = lambda do
new_storage = Match::Storage.from_params(options)
new_storage.download
return new_storage
end
encryption_factory = lambda do |stor|
new_encryption = Match::Encryption.for_storage_mode(options[:storage_mode], { 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_factory.call
encryption = encryption_factory.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_factory.call
encryption = encryption_factory.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

View File

@ -0,0 +1,96 @@
require 'match'
require 'fastlane_core'
require 'Spaceship'
def refresh_profiles(options)
register_local_storage_for_match()
profiles_tmp_dir = Dir.mktmpdir
unless options[:cert_id]
cert_type = Match.cert_type_sym(options[:type])
storage = Match::Storage.from_params(options)
storage.download
output_dir_certs = File.join(storage.prefixed_working_directory, "certs", cert_type.to_s)
matched_certs = Dir.glob("*.cer", base: output_dir_certs)
if matched_certs.empty?
FastlaneCore::UI.error("Unable to locate certificate to upate profiles")
raise "No certificates found at #{output_dir_certs}"
end
if matched_certs.length > 1
options[:cert_id] = File.basename(FastlaneCore::UI.select("Please select the certificate", matched_certs), ".cer")
else
options[:cert_id] = File.basename(matched_certs.first, ".cer")
end
if options[:cert_path].nil? && options[:p12_path].nil?
encryption = Match::Encryption.for_storage_mode(options[:storage_mode], { working_directory: storage.working_directory })
encryption.decrypt_files
tmp_certs_dir = Dir.mktmpdir
cer_file_name = "#{options[:cert_id]}.cer"
cert_path = File.join(output_dir_certs, cer_file_name)
options[:cert_path] = File.join(tmp_certs_dir, cer_file_name)
p12_file_name = "#{options[:cert_id]}.p12"
p12_path = File.join(output_dir_certs, p12_file_name)
options[:p12_path] = File.join(tmp_certs_dir, p12_file_name)
IO.copy_stream(cert_path, options[:cert_path])
IO.copy_stream(p12_path, options[:p12_path])
end
end
app_identifier = options[:app_identifier]
Spaceship::ConnectAPI.token = Spaceship::ConnectAPI::Token.from_json_file(options[:api_key_path])
if app_identifier.is_a? Array
app_identifier.each { |app_id| refresh_profile_for_app(options, app_id, profiles_tmp_dir) }
else
refresh_profile_for_app(options, app_identifier, profiles_tmp_dir)
end
end
def refresh_profile_for_app(options, app_id, profiles_tmp_dir)
provisioning_name = Fastlane::Actions.lane_context[Touchlane::SharedValues::TOUCH_BUNDLE_ID_PROFILE_NAME_MAPPING][app_id]
profiles = Spaceship::ConnectAPI::Profile.all(filter: { name: provisioning_name })
if profiles.empty?
sigh_for_app(options, app_id, provisioning_name, profiles_tmp_dir)
else
FastlaneCore::UI.important("Did find existing profile #{provisioning_name}. Removing it from dev portal.")
profiles.each { |profile| profile.delete! if profile.name == provisioning_name }
sigh_for_app(options, app_id, provisioning_name, profiles_tmp_dir)
end
Match::Importer.new.import_cert(
options,
cert_path: options[:cert_path],
p12_path: options[:p12_path],
profile_path: lane_context[Fastlane::Actions::SharedValues::SIGH_PROFILE_PATH]
)
end
def sigh_for_app(options, app_id, provisioning_name, profiles_tmp_dir)
sigh(
app_identifier: app_id,
development: options[:development],
username: options[:username] || options[:apple_id],
api_key_path: options[:api_key_path],
api_key: options[:api_key],
team_id: options[:team_id],
provisioning_name: provisioning_name,
output_path: profiles_tmp_dir,
cert_id: options[:cert_id],
force: true # will also add all available devices to this profile
)
end

View File

@ -0,0 +1,24 @@
def replace_development_certificate(options)
register_local_storage_for_match()
certs_path_tmp_dir = Dir.mktmpdir
cert(
development: true,
username: options[:username] || options[:apple_id],
api_key_path: options[:api_key_path],
api_key: options[:api_key],
team_id: options[:team_id],
output_path: certs_path_tmp_dir,
keychain_password: options[:keychain_password]
)
options[:cert_id] = lane_context[Fastlane::Actions::SharedValues::CERT_CERTIFICATE_ID]
options[:cert_path] = lane_context[Fastlane::Actions::SharedValues::CERT_FILE_PATH]
options[:p12_path] = File.join(File.dirname(options[:cert_path]), "#{options[:cert_id]}.p12")
options[:readonly] = false
refresh_profiles(options)
sh("open #{certs_path_tmp_dir}")
end

View File

@ -0,0 +1,26 @@
def install_signing_identities(options)
readonly_options = options
readonly_options[:readonly] = true
sync_signing_identities(readonly_options)
end
def sync_signing_identities(options)
register_local_storage_for_match()
match(
app_identifier: options[:app_identifier],
username: options[:username] || options[:apple_id],
api_key_path: options[:api_key_path],
api_key: options[:api_key],
team_id: options[:team_id],
type: options[:type],
readonly: options[:readonly].nil? ? true : options[:readonly],
storage_mode: options[:storage_mode],
# we can't pass signing_identities_path as parameter name since params is hardcoded in match/runner.rb
git_url: options[:signing_identities_path] || options[:git_url],
skip_docs: true,
keychain_name: options[:keychain_name],
keychain_password: options[:keychain_password]
)
end

View File

@ -1,6 +1,10 @@
require "yaml" require "yaml"
module Touchlane module Touchlane
module SharedValues
TOUCH_BUNDLE_ID_PROFILE_NAME_MAPPING = :TOUCH_BUNDLE_ID_PROFILE_NAME_MAPPING
end
class Configuration class Configuration
def initialize(type, app_identifier, apple_id, team_id, itc_team_id) def initialize(type, app_identifier, apple_id, team_id, itc_team_id)
@type = type @type = type
@ -13,6 +17,8 @@ module Touchlane
attr_reader :type, :app_identifier, :apple_id, :team_id, :itc_team_id attr_reader :type, :app_identifier, :apple_id, :team_id, :itc_team_id
def self.from_file(path, type) def self.from_file(path, type)
Fastlane::Actions.lane_context[SharedValues::TOUCH_BUNDLE_ID_PROFILE_NAME_MAPPING] = {}
configuration_hash = load_configuration_from_file(path) configuration_hash = load_configuration_from_file(path)
attrs_hash = configuration_hash["types"][type] attrs_hash = configuration_hash["types"][type]
identifiers = get_app_identifiers_from_configuration_hash(configuration_hash, type) identifiers = get_app_identifiers_from_configuration_hash(configuration_hash, type)
@ -35,8 +41,15 @@ module Touchlane
def self.get_app_identifiers_from_configuration_hash(configuration_hash, type) def self.get_app_identifiers_from_configuration_hash(configuration_hash, type)
identifier_key = "PRODUCT_BUNDLE_IDENTIFIER" identifier_key = "PRODUCT_BUNDLE_IDENTIFIER"
profile_name_key = "PROVISIONING_PROFILE_SPECIFIER"
configuration_hash["targets"].collect do |target, types| configuration_hash["targets"].collect do |target, types|
types[type][identifier_key] or raise "#{target}: There is no #{identifier_key} field in #{type}" bundle_id = types[type][identifier_key]
profile_name = types[type][profile_name_key]
Fastlane::Actions.lane_context[SharedValues::TOUCH_BUNDLE_ID_PROFILE_NAME_MAPPING][bundle_id] = profile_name
bundle_id or raise "#{target}: There is no #{identifier_key} field in #{type}"
end end
end end

View File

@ -3,28 +3,39 @@ module Touchlane
DEVELOPMENT = "development" DEVELOPMENT = "development"
ENTERPRISE = "enterprise" ENTERPRISE = "enterprise"
APP_STORE = "appstore" APP_STORE = "appstore"
ADHOC = "adhoc"
DEVELOPMENT_PREFIX = "Standard" DEVELOPMENT_PREFIX = "Standard"
ENTERPRISE_PREFIX = "Enterprise" ENTERPRISE_PREFIX = "Enterprise"
APP_STORE_PREFIX = "AppStore" APP_STORE_PREFIX = "AppStore"
ADHOC_PREFIX = "AdHoc"
private_constant :DEVELOPMENT, :ENTERPRISE, :APP_STORE private_constant :DEVELOPMENT, :ENTERPRISE, :APP_STORE, :ADHOC_PREFIX
private_constant :DEVELOPMENT_PREFIX, :ENTERPRISE_PREFIX, :APP_STORE_PREFIX private_constant :DEVELOPMENT_PREFIX, :ENTERPRISE_PREFIX, :APP_STORE_PREFIX, :ADHOC_PREFIX
def initialize(type) def initialize(type)
@type = type @type = type
@is_app_store = type == APP_STORE
@is_development = type == DEVELOPMENT
case type case type
when DEVELOPMENT, ENTERPRISE when DEVELOPMENT
@export_method = type @export_method = type
@configuration = type == DEVELOPMENT ? "Debug" : "Release" @configuration = "Debug"
@is_app_store = false @prefix = DEVELOPMENT_PREFIX
@prefix = type == DEVELOPMENT ? DEVELOPMENT_PREFIX : ENTERPRISE_PREFIX when ENTERPRISE
@export_method = type
@configuration = "Release"
@prefix = ENTERPRISE_PREFIX
when APP_STORE when APP_STORE
@export_method = "app-store" @export_method = "app-store"
@configuration = "AppStore" @configuration = "AppStore"
@is_app_store = true
@prefix = APP_STORE_PREFIX @prefix = APP_STORE_PREFIX
when ADHOC
@export_method = type
@export_method = "ad-hoc"
@prefix = ADHOC_PREFIX
else else
raise "Unknown type passed #{type}" raise "Unknown type passed #{type}"
end end
@ -32,7 +43,7 @@ module Touchlane
private_class_method :new private_class_method :new
attr_reader :export_method, :type, :configuration, :is_app_store, :prefix attr_reader :export_method, :type, :configuration, :is_app_store, :is_development, :prefix
def self.from_lane_name(lane_name) def self.from_lane_name(lane_name)
case case
@ -42,9 +53,11 @@ module Touchlane
from_type(APP_STORE) from_type(APP_STORE)
when lane_name.start_with?(DEVELOPMENT_PREFIX) when lane_name.start_with?(DEVELOPMENT_PREFIX)
from_type(DEVELOPMENT) from_type(DEVELOPMENT)
when lane_name.start_with?(ADHOC_PREFIX)
from_type(ADHOC)
else else
raise "Unable to map #{lane_name} to #{ConfigurationType.class}." raise "Unable to map #{lane_name} to #{ConfigurationType.class}."
+ "Available prefixes: #{DEVELOPMENT_PREFIX}, #{ENTERPRISE_PREFIX}, #{APP_STORE_PREFIX}" + "Available prefixes: #{DEVELOPMENT_PREFIX}, #{ENTERPRISE_PREFIX}, #{APP_STORE_PREFIX}, #{ADHOC_PREFIX}"
end end
end end
@ -52,9 +65,26 @@ module Touchlane
new(type) new(type)
end end
def self.from_account_type(account_type)
case account_type
when DEVELOPMENT_PREFIX
from_type(DEVELOPMENT)
when ENTERPRISE_PREFIX
from_type(ENTERPRISE)
when APP_STORE_PREFIX
from_type(APP_STORE)
when ADHOC_PREFIX
from_type(ADHOC)
else
raise "Unable to map #{account_type} to #{ConfigurationType.class}."
+ "Available account types: #{DEVELOPMENT_PREFIX}, #{ENTERPRISE_PREFIX}, #{APP_STORE_PREFIX}, #{ADHOC_PREFIX}"
end
end
def to_options def to_options
{ {
:type => @type, :type => @type,
:development => @is_development,
:export_method => @export_method, :export_method => @export_method,
:configuration => @configuration :configuration => @configuration
} }