fastlane-plugin-wpmreleasetoolkit 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/an_localize_libs_action.rb +8 -3
  3. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_betabuild_prechecks.rb +8 -2
  4. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_release.rb +11 -4
  5. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_codefreeze_prechecks.rb +10 -4
  6. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/buildkite_trigger_build_action.rb +90 -0
  7. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/comment_on_pr.rb +89 -0
  8. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_release_action.rb +2 -0
  9. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/gp_downloadmetadata_action.rb +1 -1
  10. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_betabuild_prechecks.rb +8 -2
  11. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_bump_version_release.rb +10 -5
  12. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_codefreeze_prechecks.rb +10 -4
  13. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_download_strings_files_from_glotpress.rb +113 -0
  14. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_generate_strings_file_from_code.rb +115 -0
  15. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb +5 -5
  16. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_localize_project.rb +6 -7
  17. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_merge_strings_files.rb +75 -0
  18. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_git_helper.rb +0 -20
  19. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_localize_helper.rb +8 -0
  20. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/git_helper.rb +3 -0
  21. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb +48 -8
  22. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/interactive_prompt_reminder.rb +93 -0
  23. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_git_helper.rb +3 -2
  24. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb +108 -173
  25. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_linter_helper.rb +207 -0
  26. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/promo_screenshots_helper.rb +3 -3
  27. data/lib/fastlane/plugin/wpmreleasetoolkit/models/file_reference.rb +1 -4
  28. data/lib/fastlane/plugin/wpmreleasetoolkit/version.rb +1 -1
  29. metadata +26 -39
  30. data/bin/drawText +0 -20
  31. data/ext/drawText/drawText/Assets/style.css +0 -1
  32. data/ext/drawText/drawText/CoreTextStack.swift +0 -113
  33. data/ext/drawText/drawText/Helpers/CommandLineHelpers.swift +0 -36
  34. data/ext/drawText/drawText/Helpers/Extensions.swift +0 -27
  35. data/ext/drawText/drawText/Helpers/FileSystemHelper.swift +0 -24
  36. data/ext/drawText/drawText/Stylesheet.swift +0 -48
  37. data/ext/drawText/drawText/TextImage.swift +0 -100
  38. data/ext/drawText/drawText/main.swift +0 -61
  39. data/ext/drawText/drawText Tests/DigitParsingTests.swift +0 -21
  40. data/ext/drawText/drawText Tests/ExtensionsTests.swift +0 -5
  41. data/ext/drawText/drawText Tests/Info.plist +0 -22
  42. data/ext/drawText/drawText Tests/StylesheetTests.swift +0 -31
  43. data/ext/drawText/drawText Tests/Test Cases/default-stylesheet.txt +0 -10
  44. data/ext/drawText/drawText Tests/Test Cases/external-styles-sample.css +0 -3
  45. data/ext/drawText/drawText Tests/Test Cases/external-styles-test.txt +0 -13
  46. data/ext/drawText/drawText Tests/Test Cases/large-text-block.txt +0 -1
  47. data/ext/drawText/drawText Tests/Test Cases/regular-text-block.txt +0 -2
  48. data/ext/drawText/drawText Tests/Test Cases/rtl-text-block.txt +0 -2
  49. data/ext/drawText/drawText Tests/Test Cases/text-size-adjustment-test.txt +0 -10
  50. data/ext/drawText/drawText Tests/TextImageTests.swift +0 -99
  51. data/ext/drawText/drawText Tests/drawText_Tests.swift +0 -14
  52. data/ext/drawText/drawText.xcodeproj/project.pbxproj +0 -508
  53. data/ext/drawText/drawText.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  54. data/ext/drawText/drawText.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  55. data/ext/drawText/drawText.xcodeproj/xcshareddata/xcschemes/drawText Tests.xcscheme +0 -57
  56. data/ext/drawText/drawText.xcodeproj/xcshareddata/xcschemes/drawText.xcscheme +0 -109
  57. data/ext/drawText/extconf.rb +0 -36
  58. data/ext/drawText/makefile.example +0 -8
  59. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_merge_translators_strings.rb +0 -106
  60. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_update_metadata.rb +0 -52
  61. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_merge_translators_strings.rb +0 -93
@@ -0,0 +1,115 @@
1
+ module Fastlane
2
+ module Actions
3
+ class IosGenerateStringsFileFromCodeAction < Action
4
+ def self.run(params)
5
+ files = files_matching(paths: params[:paths], exclude: params[:exclude])
6
+ flags = [('-q' if params[:quiet]), ('-SwiftUI' if params[:swiftui])].compact
7
+ flags += Array(params[:routines]).flat_map { |routine| ['-s', routine] }
8
+ cmd = ['genstrings', '-o', params[:output_dir], *flags, *files]
9
+ out = Actions.sh_control_output(*cmd, print_command: FastlaneCore::Globals.verbose?, print_command_output: true)
10
+ out = out.scrub.strip.split("\n")
11
+ errors = out.select { |line| line.include?('genstrings: error: ') }
12
+ UI.user_error!(errors.join("\n")) unless !params[:fail_on_error] || errors.empty?
13
+ out
14
+ end
15
+
16
+ # Adds the proper `**/*.{m,swift}` to the list of paths
17
+ def self.glob_pattern(path)
18
+ if path.end_with?('**') || path.end_with?('**/')
19
+ File.join(path, '*.{m,swift}')
20
+ elsif File.directory?(path) || path.end_with?('/')
21
+ File.join(path, '**', '*.{m,swift}')
22
+ else
23
+ path
24
+ end
25
+ end
26
+
27
+ def self.files_matching(paths:, exclude:)
28
+ globbed_paths = paths.map { |p| glob_pattern(p) }
29
+ Dir.glob(globbed_paths).reject do |file|
30
+ exclude&.any? { |ex| File.fnmatch?(ex, file) }
31
+ end
32
+ end
33
+
34
+ #####################################################
35
+ # @!group Documentation
36
+ #####################################################
37
+
38
+ def self.description
39
+ 'Generate the .strings files from your Objective-C and Swift code'
40
+ end
41
+
42
+ def self.details
43
+ <<~DETAILS
44
+ Uses `genstrings` to generate the `.strings` files from your Objective-C and Swift code.
45
+ (especially `Localizable.strings` but it could generate more if the code uses custom tables).
46
+
47
+ You can provide a list of paths to scan but also paths to exclude. Both supports glob patterns.
48
+ You can also optionally provide a list of custom "routines" (aka macros or functions) that
49
+ `genstrings` should parse in addition to the usual `NSLocalizedString`. (see `-s` option of `genstrings`).
50
+
51
+ Tip: support for custom routines is useful if some of your targets define a helper function e.g.
52
+ `PodLocalizedString` to wrap calls to `Bundle.localizedString(forKey: key, value: value, table: nil)`,
53
+ just like the build-in `NSLocalizedString` does, but providing a custom bundle to look up the strings from.
54
+ DETAILS
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ FastlaneCore::ConfigItem.new(key: :paths,
60
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_PATHS',
61
+ description: 'Array of paths to scan for `.m` and `.swift` files. The entries can also contain glob patterns',
62
+ type: Array,
63
+ default_value: ['.']),
64
+ FastlaneCore::ConfigItem.new(key: :exclude,
65
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_EXCLUDE',
66
+ description: 'Array of paths or glob patterns to exclude from scanning',
67
+ type: Array,
68
+ default_value: []),
69
+ FastlaneCore::ConfigItem.new(key: :routines,
70
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_ROUTINES',
71
+ description: 'Base name of the alternate methods to be parsed in addition to the standard `NSLocalizedString()` one. See the `-s` option in `man genstrings`',
72
+ type: Array,
73
+ default_value: []),
74
+ FastlaneCore::ConfigItem.new(key: :quiet,
75
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_QUIET',
76
+ description: 'In quiet mode, `genstrings` will log warnings about duplicate values, but not about duplicate comments',
77
+ is_string: false, # Boolean
78
+ default_value: true),
79
+ FastlaneCore::ConfigItem.new(key: :swiftui,
80
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_SWIFTUI',
81
+ description: "Should we include SwiftUI's `Text()` when parsing code with `genstrings`",
82
+ is_string: false, # Boolean
83
+ default_value: false),
84
+ FastlaneCore::ConfigItem.new(key: :output_dir,
85
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_OUTPUT_DIR',
86
+ description: 'The path to the directory where the generated `.strings` files should be created',
87
+ type: String),
88
+ FastlaneCore::ConfigItem.new(key: :fail_on_error,
89
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_FAIL_ON_ERROR',
90
+ description: 'If true, will fail with user_error! if `genstrings` printed any error while parsing',
91
+ is_string: false, # Boolean
92
+ default_value: true),
93
+ ]
94
+ end
95
+
96
+ def self.return_type
97
+ # Describes what type of data is expected to be returned
98
+ # see RETURN_TYPES in https://github.com/fastlane/fastlane/blob/master/fastlane/lib/fastlane/action.rb
99
+ :array_of_strings
100
+ end
101
+
102
+ def self.return_value
103
+ 'List of warning lines generated by genstrings on stdout'
104
+ end
105
+
106
+ def self.authors
107
+ ['Automattic']
108
+ end
109
+
110
+ def self.is_supported?(platform)
111
+ [:ios, :mac].include?(platform)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -17,8 +17,8 @@ module Fastlane
17
17
  def self.run_linter(params)
18
18
  UI.message 'Linting localizations for parameter placeholders consistency...'
19
19
 
20
- require_relative '../../helper/ios/ios_l10n_helper'
21
- helper = Fastlane::Helper::Ios::L10nHelper.new(
20
+ require_relative '../../helper/ios/ios_l10n_linter_helper'
21
+ helper = Fastlane::Helper::Ios::L10nLinterHelper.new(
22
22
  install_path: resolve_path(params[:install_path]),
23
23
  version: params[:version]
24
24
  )
@@ -92,7 +92,7 @@ module Fastlane
92
92
  description: 'The path where to install the SwiftGen tooling needed to run the linting process. If a relative path, should be relative to your repo_root',
93
93
  type: String,
94
94
  optional: true,
95
- default_value: "vendor/swiftgen/#{Fastlane::Helper::Ios::L10nHelper::SWIFTGEN_VERSION}"
95
+ default_value: "vendor/swiftgen/#{Fastlane::Helper::Ios::L10nLinterHelper::SWIFTGEN_VERSION}"
96
96
  ),
97
97
  FastlaneCore::ConfigItem.new(
98
98
  key: :version,
@@ -100,7 +100,7 @@ module Fastlane
100
100
  description: 'The version of SwiftGen to install and use for linting',
101
101
  type: String,
102
102
  optional: true,
103
- default_value: Fastlane::Helper::Ios::L10nHelper::SWIFTGEN_VERSION
103
+ default_value: Fastlane::Helper::Ios::L10nLinterHelper::SWIFTGEN_VERSION
104
104
  ),
105
105
  FastlaneCore::ConfigItem.new(
106
106
  key: :input_dir,
@@ -115,7 +115,7 @@ module Fastlane
115
115
  description: 'The language that should be used as the base language that every other language will be compared against',
116
116
  type: String,
117
117
  optional: true,
118
- default_value: Fastlane::Helper::Ios::L10nHelper::DEFAULT_BASE_LANG
118
+ default_value: Fastlane::Helper::Ios::L10nLinterHelper::DEFAULT_BASE_LANG
119
119
  ),
120
120
  FastlaneCore::ConfigItem.new(
121
121
  key: :only_langs,
@@ -16,20 +16,19 @@ module Fastlane
16
16
  #####################################################
17
17
 
18
18
  def self.description
19
- 'Gathers the string to localise'
19
+ 'Gathers the strings to localise. Deprecated'
20
20
  end
21
21
 
22
22
  def self.details
23
- 'Gathers the string to localise'
23
+ 'Gathers the strings to localise. Deprecated in favor of the new `ios_generate_strings_file_from_code`'
24
24
  end
25
25
 
26
- def self.available_options
26
+ def self.category
27
+ :deprecated
27
28
  end
28
29
 
29
- def self.output
30
- end
31
-
32
- def self.return_value
30
+ def self.deprecated_notes
31
+ 'This action is deprecated in favor of `ios_generate_strings_file_from_code`'
33
32
  end
34
33
 
35
34
  def self.authors
@@ -0,0 +1,75 @@
1
+ module Fastlane
2
+ module Actions
3
+ class IosMergeStringsFilesAction < Action
4
+ def self.run(params)
5
+ UI.message "Merging strings files: #{params[:paths].inspect}"
6
+
7
+ duplicates = Fastlane::Helper::Ios::L10nHelper.merge_strings(paths: params[:paths], output_path: params[:destination])
8
+ duplicates.each do |dup_key|
9
+ UI.important "Duplicate key found while merging the `.strings` files: `#{dup_key}`"
10
+ end
11
+ duplicates
12
+ end
13
+
14
+ #####################################################
15
+ # @!group Documentation
16
+ #####################################################
17
+
18
+ def self.description
19
+ 'Merge multiple `.strings` files into one'
20
+ end
21
+
22
+ def self.details
23
+ <<~DETAILS
24
+ Merge multiple `.strings` files into one.
25
+
26
+ Especially useful to prepare a single `.strings` file merging strings from both `Localizable.strings` from
27
+ the app code — typically previously extracted from `ios_generate_strings_file_from_code` —
28
+ and string files like `InfoPlist.strings` — which values may not be generated from the codebase but
29
+ manually maintained by developers.
30
+
31
+ The action only supports merging files which are in the OpenStep (`"key" = "value";`) text format (which is
32
+ the most common format for `.strings` files, and the one generated by `genstrings`), but can handle the case
33
+ of different files using different encodings (UTF8 vs UTF16) and is able to detect and report duplicates.
34
+ It does not handle `.strings` files in XML or binary-plist formats (which are valid but more rare)
35
+ DETAILS
36
+ end
37
+
38
+ def self.available_options
39
+ [
40
+ FastlaneCore::ConfigItem.new(
41
+ key: :paths,
42
+ env_name: 'FL_IOS_MERGE_STRINGS_FILES_PATHS',
43
+ description: 'The paths of all the `.strings` files to merge together',
44
+ type: Array,
45
+ optional: false
46
+ ),
47
+ FastlaneCore::ConfigItem.new(
48
+ key: :destination,
49
+ env_name: 'FL_IOS_MERGE_STRINGS_FILES_DESTINATION',
50
+ description: 'The path of the merged `.strings` file to generate. If nil, the merge will happen in-place in the first file in the `paths:` list',
51
+ type: String,
52
+ optional: true,
53
+ default_value: nil
54
+ ),
55
+ ]
56
+ end
57
+
58
+ def self.return_type
59
+ :array_of_strings
60
+ end
61
+
62
+ def self.return_value
63
+ 'The list of duplicate keys found while merging the various `.strings` files'
64
+ end
65
+
66
+ def self.authors
67
+ ['automattic']
68
+ end
69
+
70
+ def self.is_supported?(platform)
71
+ [:ios, :mac].include? platform
72
+ end
73
+ end
74
+ end
75
+ end
@@ -27,26 +27,6 @@ module Fastlane
27
27
  )
28
28
  end
29
29
  end
30
-
31
- # Calls the `tools/update-translations.sh` script from the project repo, then lint them using the provided gradle task
32
- #
33
- # Deprecated. Use the `android_download_translations` action instead.
34
- #
35
- # @env PROJECT_ROOT_FOLDER The path to the git root of the project
36
- # @env PROJECT_NAME The name of the directory containing the project code (especially containing the `build.gradle` file)
37
- #
38
- # @param [String] validate_translation_command The name of the gradle task to run to validate the translations
39
- #
40
- # @todo Remove this once every client has migrated to `android_download_translations` and we got rid of that legacy action.
41
- #
42
- def self.update_metadata(validate_translation_command)
43
- Action.sh('./tools/update-translations.sh')
44
- Action.sh('git', 'submodule', 'update', '--init', '--recursive')
45
- Action.sh('./gradlew', validate_translation_command)
46
-
47
- res_dir = File.join(ENV['PROJECT_ROOT_FOLDER'], ENV['PROJECT_NAME'], 'src', 'main', 'res')
48
- Fastlane::Helper::GitHelper.commit(message: 'Update translations', files: res_dir, push: true)
49
- end
50
30
  end
51
31
  end
52
32
  end
@@ -92,6 +92,14 @@ module Fastlane
92
92
  UI.user_error!("String #{string_name} [#{string_content}] was found in library #{library[:library]} but not in the main file.")
93
93
  end
94
94
 
95
+ # Merge strings from a library into the strings.xml of the main app
96
+ #
97
+ # @param [String] main Path to the main strings.xml file (something like `…/res/values/strings.xml`)
98
+ # @param [Hash] library Hash describing the library to merge. The Hash should contain the following keys:
99
+ # - `:library`: The human readable name of the library, used to display in console messages
100
+ # - `:strings_path`: The path to the strings.xml file of the library to merge into the main one
101
+ # - `:exclusions`: An array of strings keys to exclude during merge. Any of those keys from the library's `strings.xml` will be skipped and won't be merged into the main one.
102
+ # @return [Boolean] True if at least one string from the library has been added to (or has updated) the main strings file.
95
103
  def self.merge_lib(main, library)
96
104
  UI.message("Merging #{library[:library]} strings into #{main}")
97
105
  main_strings = File.open(main) { |f| Nokogiri::XML(f, nil, Encoding::UTF_8.to_s) }
@@ -5,6 +5,9 @@ module Fastlane
5
5
  # Helper methods to execute git-related operations
6
6
  #
7
7
  module GitHelper
8
+ # Fallback default branch of the client repository.
9
+ DEFAULT_GIT_BRANCH = 'trunk'.freeze
10
+
8
11
  # Checks if the given path, or current directory if no path is given, is
9
12
  # inside a Git repository
10
13
  #
@@ -1,23 +1,37 @@
1
1
  require 'fastlane_core/ui/ui'
2
2
  require 'octokit'
3
3
  require 'open-uri'
4
+ require 'securerandom'
4
5
 
5
6
  module Fastlane
6
7
  UI = FastlaneCore::UI unless Fastlane.const_defined?('UI')
7
8
 
8
9
  module Helper
9
10
  class GithubHelper
11
+ def self.github_token!
12
+ token = [
13
+ 'GHHELPER_ACCESS', # For historical reasons / backward compatibility
14
+ 'GITHUB_TOKEN', # Used by the `gh` CLI tool
15
+ ].map { |key| ENV[key] }
16
+ .compact
17
+ .first
18
+
19
+ token || UI.user_error!('Please provide a GitHub authentication token via the `GITHUB_TOKEN` environment variable')
20
+ end
21
+
10
22
  def self.github_client
11
- client = Octokit::Client.new(access_token: ENV['GHHELPER_ACCESS'])
23
+ @@client ||= begin
24
+ client = Octokit::Client.new(access_token: github_token!)
12
25
 
13
- # Fetch the current user
14
- user = client.user
15
- UI.message("Logged in as: #{user.name}")
26
+ # Fetch the current user
27
+ user = client.user
28
+ UI.message("Logged in as: #{user.name}")
16
29
 
17
- # Auto-paginate to ensure we're not missing data
18
- client.auto_paginate = true
30
+ # Auto-paginate to ensure we're not missing data
31
+ client.auto_paginate = true
19
32
 
20
- client
33
+ client
34
+ end
21
35
  end
22
36
 
23
37
  def self.get_milestone(repository, release)
@@ -117,8 +131,11 @@ module Fastlane
117
131
  file_name = File.basename(file_path)
118
132
  download_path = File.join(download_folder, file_name)
119
133
 
134
+ download_url = github_client.contents(repository,
135
+ path: file_path,
136
+ ref: tag).download_url
120
137
  begin
121
- uri = URI.parse("https://raw.githubusercontent.com/#{repository}/#{tag}/#{file_path}")
138
+ uri = URI.parse(download_url)
122
139
  uri.open do |remote_file|
123
140
  File.write(download_path, remote_file.read)
124
141
  end
@@ -128,6 +145,29 @@ module Fastlane
128
145
 
129
146
  download_path
130
147
  end
148
+
149
+ # Creates (or updates an existing) GitHub PR Comment
150
+ def self.comment_on_pr(project_slug:, pr_number:, body:, reuse_identifier: SecureRandom.uuid)
151
+ client = github_client
152
+ comments = client.issue_comments(project_slug, pr_number)
153
+
154
+ reuse_marker = "<!-- REUSE_ID: #{reuse_identifier} -->"
155
+
156
+ existing_comment = comments.find do |comment|
157
+ # Only match comments posted by the owner of the GitHub Token, and with the given reuse ID
158
+ comment.user.id == client.user.id and comment.body.include?(reuse_marker)
159
+ end
160
+
161
+ comment_body = reuse_marker + body
162
+
163
+ if existing_comment.nil?
164
+ client.add_comment(project_slug, pr_number, comment_body)
165
+ else
166
+ client.update_comment(project_slug, existing_comment.id, comment_body)
167
+ end
168
+
169
+ reuse_identifier
170
+ end
131
171
  end
132
172
  end
133
173
  end
@@ -0,0 +1,93 @@
1
+ require 'fastlane_core'
2
+
3
+ # The features in this file are controlled by the following ENV vars:
4
+ #
5
+ # @env `FASTLANE_PROMPT_REMINDER_DISABLE_AUTO_PATCH`
6
+ # If this variable is set, it will disable the auto-application of the monkey patch. In such case,
7
+ # `UI.input`, `UI.confirm`, `UI.select` and `UI.password` methods won't be automatically patched
8
+ # unless you explicitly call `monkey_patch_interactive_prompts_with_reminder` yourself.
9
+ #
10
+ # @env `FASTLANE_PROMPT_REMINDER_MESSAGE`
11
+ # - If not set, then while auto-patching the `UI.…` methods, it will NOT make the patched methods
12
+ # speak any vocal message – and instead will only emit a beep and make your Terminal icon jump in the Dock.
13
+ # - If set to `default`, `true`, `yes` or `1`, then while auto-patching the `UI.…` methods, it will
14
+ # make the patched methods announce the default message.
15
+ # - If set to any other string, it will make the patched methods use that string as the message to announce
16
+ # during the reminders
17
+ # - NOTE: This env var only has an effect if the other `FASTLANE_PROMPT_REMINDER_DISABLE_AUTO_PATCH` env var
18
+ # is _not_ set (and thus the `UI.…` methods _are_ auto-patched), because it only affects how auto-patching is done.
19
+ #
20
+ # @env `FASTLANE_PROMPT_REMINDER_DELAYS`
21
+ # The delays (in seconds) to use when monkey-patching the `UI.…` methods to wrap them around `with_reminder`,
22
+ # separated by a comma (e.g. `60,300,900`). If unset, will use the default delays of `30,180,600`.
23
+
24
+ module FastlaneCore
25
+ # NOTE: FastlaneCore::UI delegates to the FastlaneCore::Shell implementation when output is the terminal
26
+ class Shell
27
+ DEFAULT_PROMPT_REMINDER_MESSAGE = 'An interactive prompt is waiting for you in the Terminal!'.freeze
28
+ DEFAULT_PROMPT_REMINDER_DELAYS = [30, 180, 600].freeze
29
+
30
+ # Calls the block given and remind the user with a vocal message if the block does not return after specific delays.
31
+ #
32
+ # Especially useful when using a block which calls methods that are interactive, in order to remind the user
33
+ # to answer the interactive prompt if they forgot about it after some delays.
34
+ #
35
+ # Example usage:
36
+ #
37
+ # text = with_reminder do
38
+ # puts "Enter some text:"
39
+ # $stdout.getch
40
+ # end
41
+ #
42
+ # @param [Double,Array<Double>] after
43
+ # Delay or list of delays to wait for before pronouncing the reminder message.
44
+ # If an array of values is passed, the message will be pronounced multiple times, after having waited for the subsequent delays in turn.
45
+ # Defaults to reminding after 30s, then 3mn, then 10mn.
46
+ # @param [String] message
47
+ # The message to pronounce out loud after the delay has passed, if the block hasn't returned beforehand.
48
+ # @return The same value that the blocks might return
49
+ #
50
+ def self.with_reminder(after: DEFAULT_PROMPT_REMINDER_DELAYS, message: DEFAULT_PROMPT_REMINDER_MESSAGE)
51
+ delays_list = Array(after.dup)
52
+ thread = Thread.new do
53
+ until delays_list.empty?
54
+ sleep(delays_list.shift)
55
+ $stdout.beep
56
+ system('say', message) unless message.nil?
57
+ end
58
+ end
59
+ # execute the interactive code
60
+ res = yield
61
+ # if we replied before the timeout, kill the thread so message won't be triggered
62
+ thread.kill
63
+ # If the block given returned a value, pass it
64
+ return res
65
+ end
66
+
67
+ # Monkey-Patch fastlane's `UI.input`, `UI.confirm`, `UI.select` and `UI.password` interactive methods
68
+ # (which delegate to `FastlaneCore::Shell` when output is the terminal)
69
+ #
70
+ # Once you call this method, any invocation of `UI.input`, `UI.confirm`, `UI.select` or `UI.password`
71
+ # anywhere in Fastlane (by your Fastfile, an action, …) will be wrapped in a call to with_reminder automatically.
72
+ #
73
+ def self.monkey_patch_interactive_prompts_with_reminder(after: DEFAULT_PROMPT_REMINDER_DELAYS, message: DEFAULT_PROMPT_REMINDER_MESSAGE)
74
+ %i[input confirm select password].each do |method_name|
75
+ old_method = instance_method(method_name)
76
+
77
+ define_method(method_name) do |*args|
78
+ FastlaneCore::Shell.with_reminder(after: after, message: message) { old_method.bind(self).call(*args) }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ # Apply Monkey patch
86
+ unless ENV['FASTLANE_PROMPT_REMINDER_DISABLE_AUTO_PATCH']
87
+ message = ENV['FASTLANE_PROMPT_REMINDER_MESSAGE']
88
+ message = FastlaneCore::Shell::DEFAULT_PROMPT_REMINDER_MESSAGE if %w[default true yes 1].include?(message&.downcase)
89
+ delays = ENV['FASTLANE_PROMPT_REMINDER_DELAYS']&.split(',')&.map(&:to_i) || FastlaneCore::Shell::DEFAULT_PROMPT_REMINDER_DELAYS
90
+
91
+ FastlaneCore::UI.verbose("Monkey-patching the UI interactive methods to add a reminder (#{delays.inspect}, #{message.inspect})")
92
+ FastlaneCore::Shell.monkey_patch_interactive_prompts_with_reminder(after: delays, message: message)
93
+ end
@@ -35,8 +35,9 @@ module Fastlane
35
35
  # @env PROJECT_ROOT_FOLDER The path to the git root of the project
36
36
  # @env PROJECT_NAME The name of the directory containing the project code (especially containing the `build.gradle` file)
37
37
  #
38
- # @todo Migrate the scripts, currently in each host repo and called by this method, to be helpers and actions
39
- # in the release-toolkit instead, and move this code away from `ios_git_helper`.
38
+ # @deprecated This method is only used by the `ios_localize_project` action, which is itself deprecated
39
+ # in favor of the new `ios_generate_strings_file_from_code` action
40
+ # @todo [Next Major] Remove this method once we fully remove `ios_localize_project`
40
41
  #
41
42
  def self.localize_project
42
43
  Action.sh("cd #{get_from_env!(key: 'PROJECT_ROOT_FOLDER')} && ./Scripts/localize.py")