fastlane-plugin-wpmreleasetoolkit 14.11.3 → 15.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_download_translations_action.rb +5 -1
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/get_prs_between_tags.rb +4 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/gp_downloadmetadata_action.rb +4 -1
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_download_strings_files_from_glotpress.rb +77 -15
- data/lib/fastlane/plugin/wpmreleasetoolkit/env_manager/env_manager.rb +39 -5
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_localize_helper.rb +23 -5
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/config_item_helper.rb +17 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/glotpress_downloader.rb +76 -42
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb +15 -14
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/metadata_download_helper.rb +28 -9
- data/lib/fastlane/plugin/wpmreleasetoolkit/version.rb +1 -1
- metadata +4 -5
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_build_preflight.rb +0 -56
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_build_preflight.rb +0 -79
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f47aea4602fae982122ed3c370c7cbc3330ebe242781ff4abffb4498016f384c
|
|
4
|
+
data.tar.gz: e4526ac1fcbb27ece5e15fc8a11ea60d453c2bbd1ab34a8f1c88040f590e31f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 297833bfc56d46af40b9771485fe42cc5b2e54c910ddf92ea2701e50088bb4015176ed988544e593128569e3f410093cb0421976b32167e4c9755c423fc44c0d
|
|
7
|
+
data.tar.gz: 39d1cd8e4a1cc8fde878d10538cc5a49cb6b2fa58ad2f2a80fb3d1c2ea4fa830c8e4803f7052fdbd243619b4dcc60a150f4b522504f218327dd4145f3b15dee5
|
data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_download_translations_action.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../../helper/config_item_helper'
|
|
4
|
+
|
|
3
5
|
# This action is the new version of android_update_metadata (AndroidUpdateMetadataAction) and should now be used instead of that one
|
|
4
6
|
|
|
5
7
|
module Fastlane
|
|
@@ -19,7 +21,8 @@ module Fastlane
|
|
|
19
21
|
res_dir: res_dir,
|
|
20
22
|
glotpress_project_url: params[:glotpress_url],
|
|
21
23
|
glotpress_filters: params[:status_filter].map { |s| { status: s } },
|
|
22
|
-
locales_map: params[:locales]
|
|
24
|
+
locales_map: params[:locales],
|
|
25
|
+
fail_on_error: params[:fail_on_error]
|
|
23
26
|
)
|
|
24
27
|
|
|
25
28
|
# Update submodules then lint translations
|
|
@@ -99,6 +102,7 @@ module Fastlane
|
|
|
99
102
|
type: Boolean,
|
|
100
103
|
default_value: false
|
|
101
104
|
),
|
|
105
|
+
Fastlane::Helper::ConfigItemHelper.opt_in_fail_on_error_config_item,
|
|
102
106
|
]
|
|
103
107
|
end
|
|
104
108
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'fastlane/action'
|
|
4
|
+
require_relative '../../helper/config_item_helper'
|
|
4
5
|
require_relative '../../helper/github_helper'
|
|
5
6
|
|
|
6
7
|
module Fastlane
|
|
@@ -25,6 +26,8 @@ module Fastlane
|
|
|
25
26
|
config_file_path: config_file_path
|
|
26
27
|
)
|
|
27
28
|
rescue StandardError => e
|
|
29
|
+
raise if params[:fail_on_error]
|
|
30
|
+
|
|
28
31
|
error_msg = "❌ Error computing the list of PRs since #{previous_tag || 'last release'}: `#{e.message}`"
|
|
29
32
|
UI.important(error_msg)
|
|
30
33
|
error_msg # Use error message as GitHub Release body to help us be aware of what went wrong.
|
|
@@ -102,6 +105,7 @@ module Fastlane
|
|
|
102
105
|
'See https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuration-options',
|
|
103
106
|
optional: true,
|
|
104
107
|
type: String),
|
|
108
|
+
Fastlane::Helper::ConfigItemHelper.opt_in_fail_on_error_config_item,
|
|
105
109
|
Fastlane::Helper::GithubHelper.github_token_config_item,
|
|
106
110
|
]
|
|
107
111
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'fastlane/action'
|
|
4
4
|
require_relative '../../helper/metadata_download_helper'
|
|
5
|
+
require_relative '../../helper/config_item_helper'
|
|
5
6
|
|
|
6
7
|
module Fastlane
|
|
7
8
|
module Actions
|
|
@@ -13,12 +14,13 @@ module Fastlane
|
|
|
13
14
|
UI.message "Source locale: #{params[:source_locale].nil? ? '-' : params[:source_locale]}"
|
|
14
15
|
UI.message "Path: #{params[:download_path]}"
|
|
15
16
|
UI.message "Auto-retry: #{params[:auto_retry]}"
|
|
17
|
+
UI.message "Fail on error: #{params[:fail_on_error]}"
|
|
16
18
|
|
|
17
19
|
# Check download path
|
|
18
20
|
FileUtils.mkdir_p(params[:download_path])
|
|
19
21
|
|
|
20
22
|
# Download
|
|
21
|
-
downloader = Fastlane::Helper::MetadataDownloader.new(params[:download_path], params[:target_files], params[:auto_retry])
|
|
23
|
+
downloader = Fastlane::Helper::MetadataDownloader.new(params[:download_path], params[:target_files], params[:auto_retry], fail_on_error: params[:fail_on_error])
|
|
22
24
|
|
|
23
25
|
params[:locales].each do |loc|
|
|
24
26
|
if loc.is_a?(Array)
|
|
@@ -77,6 +79,7 @@ module Fastlane
|
|
|
77
79
|
type: FastlaneCore::Boolean,
|
|
78
80
|
optional: true,
|
|
79
81
|
default_value: true),
|
|
82
|
+
Fastlane::Helper::ConfigItemHelper.opt_in_fail_on_error_config_item,
|
|
80
83
|
]
|
|
81
84
|
end
|
|
82
85
|
|
data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_download_strings_files_from_glotpress.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
require_relative '../../helper/config_item_helper'
|
|
5
|
+
|
|
3
6
|
module Fastlane
|
|
4
7
|
module Actions
|
|
5
8
|
class IosDownloadStringsFilesFromGlotpressAction < Action
|
|
@@ -17,33 +20,91 @@ module Fastlane
|
|
|
17
20
|
destination = File.join(lproj_dir, "#{params[:table_basename]}.strings")
|
|
18
21
|
FileUtils.mkdir_p(lproj_dir)
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
download_and_replace_strings_file(
|
|
21
24
|
project_url: params[:project_url],
|
|
22
25
|
locale: glotpress_locale,
|
|
23
26
|
filters: params[:filters],
|
|
24
|
-
destination: destination
|
|
27
|
+
destination: destination,
|
|
28
|
+
table_basename: params[:table_basename],
|
|
29
|
+
skip_file_validation: params[:skip_file_validation],
|
|
30
|
+
fail_on_error: params[:fail_on_error]
|
|
25
31
|
)
|
|
26
|
-
# Do a quick check of the downloaded `.strings` file to ensure it looks valid
|
|
27
|
-
validate_strings_file(destination) unless params[:skip_file_validation]
|
|
28
32
|
end
|
|
29
33
|
end
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
def self.download_and_replace_strings_file(project_url:, locale:, filters:, destination:, table_basename:, skip_file_validation:, fail_on_error:)
|
|
36
|
+
if File.exist?(destination) && !File.file?(destination)
|
|
37
|
+
report_error("The destination `#{destination}` exists but is not a regular file", fail_on_error: fail_on_error)
|
|
38
|
+
return false
|
|
39
|
+
end
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
destination_mode = File.exist?(destination) ? File.stat(destination).mode & 0o7777 : 0o644
|
|
42
|
+
Tempfile.create([table_basename, '.strings'], File.dirname(destination)) do |temporary_file|
|
|
43
|
+
downloaded = Fastlane::Helper::Ios::L10nHelper.download_glotpress_export_file(
|
|
44
|
+
project_url: project_url,
|
|
45
|
+
locale: locale,
|
|
46
|
+
filters: filters,
|
|
47
|
+
destination: temporary_file,
|
|
48
|
+
fail_on_error: fail_on_error
|
|
42
49
|
)
|
|
50
|
+
return false unless downloaded
|
|
51
|
+
|
|
52
|
+
temporary_file.flush
|
|
53
|
+
# Do a quick check of the downloaded `.strings` file to ensure it looks valid
|
|
54
|
+
validate_strings_file(temporary_file.path, display_path: destination, fail_on_error: fail_on_error) unless skip_file_validation
|
|
55
|
+
File.chmod(destination_mode, temporary_file.path)
|
|
56
|
+
temporary_file.close
|
|
57
|
+
File.rename(temporary_file.path, destination)
|
|
43
58
|
end
|
|
59
|
+
true
|
|
60
|
+
rescue FastlaneCore::Interface::FastlaneError
|
|
61
|
+
raise
|
|
44
62
|
rescue StandardError => e
|
|
45
|
-
|
|
63
|
+
report_error("Error writing downloaded locale `#{locale}` — #{e.message} (#{destination})", fail_on_error: fail_on_error)
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
private_class_method :download_and_replace_strings_file
|
|
67
|
+
|
|
68
|
+
# Validate that a `.strings` file downloaded from GlotPress seems valid and does not contain empty translations
|
|
69
|
+
def self.validate_strings_file(path, display_path: path, fail_on_error: false)
|
|
70
|
+
unless File.exist?(path)
|
|
71
|
+
report_error("The file exported from GlotPress was not created (`#{display_path}`)", fail_on_error: fail_on_error) if fail_on_error
|
|
72
|
+
return
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if File.empty?(path)
|
|
76
|
+
report_error("The file exported from GlotPress is empty (`#{display_path}`)", fail_on_error: fail_on_error) if fail_on_error
|
|
77
|
+
return
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
translations = nil
|
|
81
|
+
begin
|
|
82
|
+
translations = Fastlane::Helper::Ios::L10nHelper.read_strings_file_as_hash(path: path)
|
|
83
|
+
rescue StandardError => e
|
|
84
|
+
report_error("Error while validating the file exported from GlotPress (`#{display_path}`) - #{e.message.chomp}", fail_on_error: fail_on_error)
|
|
85
|
+
return
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
unless translations.is_a?(Hash) && translations.all? { |key, value| key.is_a?(String) && value.is_a?(String) }
|
|
89
|
+
report_error("The file exported from GlotPress is not a string-to-string dictionary (`#{display_path}`)", fail_on_error: fail_on_error)
|
|
90
|
+
return
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
empty_keys = translations.select { |_, value| value.nil? || value.empty? }.keys.sort
|
|
94
|
+
return if empty_keys.empty?
|
|
95
|
+
|
|
96
|
+
report_error(
|
|
97
|
+
"Found empty translations in `#{display_path}` for the following keys: #{empty_keys.inspect}.\n" \
|
|
98
|
+
+ "This is likely a GlotPress bug, and will lead to copies replaced by empty text in the UI.\n" \
|
|
99
|
+
+ 'Please report this to the GlotPress team, and fix the file locally before continuing.',
|
|
100
|
+
fail_on_error: fail_on_error
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.report_error(message, fail_on_error:)
|
|
105
|
+
fail_on_error ? UI.user_error!(message) : UI.error(message)
|
|
46
106
|
end
|
|
107
|
+
private_class_method :report_error
|
|
47
108
|
|
|
48
109
|
#####################################################
|
|
49
110
|
# @!group Documentation
|
|
@@ -92,6 +153,7 @@ module Fastlane
|
|
|
92
153
|
type: Fastlane::Boolean,
|
|
93
154
|
optional: true,
|
|
94
155
|
default_value: false),
|
|
156
|
+
Fastlane::Helper::ConfigItemHelper.opt_in_fail_on_error_config_item,
|
|
95
157
|
]
|
|
96
158
|
end
|
|
97
159
|
|
|
@@ -15,10 +15,22 @@ module Fastlane
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
# Set up by loading the .env file with the given name.
|
|
18
|
+
#
|
|
19
|
+
# When `mutate_env` is true (the default), values from the .env file are
|
|
20
|
+
# layered into the process `ENV` using no-override semantics: keys already
|
|
21
|
+
# set in `ENV` (e.g. by CI) win. This lets fastlane actions that look up
|
|
22
|
+
# values via `ENV.fetch(...)` for their `default_value:` find them without
|
|
23
|
+
# the caller having to thread them through explicitly.
|
|
24
|
+
#
|
|
25
|
+
# Pass `mutate_env: false` to keep `ENV` pristine — values are still
|
|
26
|
+
# accessible via `get_required_env!`, but only through this instance.
|
|
27
|
+
# Useful for tests that want isolation, or for callers that prefer to
|
|
28
|
+
# control `ENV` themselves.
|
|
18
29
|
def initialize(
|
|
19
30
|
env_file_name:,
|
|
20
31
|
env_file_folder: File.join(Dir.home, '.a8c-apps'),
|
|
21
32
|
example_env_file_path: 'fastlane/example.env',
|
|
33
|
+
mutate_env: true,
|
|
22
34
|
print_error_lambda: ->(message) { FastlaneCore::UI.user_error!(message) },
|
|
23
35
|
print_warning_lambda: ->(message) { FastlaneCore::UI.important(message) }
|
|
24
36
|
)
|
|
@@ -31,10 +43,30 @@ module Fastlane
|
|
|
31
43
|
@print_warning_lambda.call("Warning: env file not found at #{@env_path}. Environment variables may not be loaded.")
|
|
32
44
|
end
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
46
|
+
unless mutate_env
|
|
47
|
+
@loaded_env = File.exist?(@env_path) ? Dotenv.parse(@env_path) : {}
|
|
48
|
+
@mutations = {}
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# `load` rather than `parse` so interpolated values (`B=${A}`) resolve
|
|
53
|
+
# against the process `ENV`; `parse` resolves them against the file's own values.
|
|
54
|
+
env_before = ENV.to_h
|
|
55
|
+
@loaded_env = File.exist?(@env_path) ? Dotenv.load(@env_path) : {}
|
|
56
|
+
# Records the value this instance wrote for each key it added. On restore,
|
|
57
|
+
# we delete only if `ENV[key]` still matches — if a later caller overwrote
|
|
58
|
+
# it, their value is left alone.
|
|
59
|
+
@mutations = ENV.to_h.reject { |key, _| env_before.key?(key) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Remove from `ENV` any keys this instance added via `mutate_env: true`,
|
|
63
|
+
# but only if the value is still the one we wrote. Keys that a later
|
|
64
|
+
# caller has overwritten are left untouched.
|
|
65
|
+
# Idempotent — calling more than once is safe. Used by `reset!` and
|
|
66
|
+
# available for callers that want to roll back manually.
|
|
67
|
+
def restore_env!
|
|
68
|
+
@mutations.each { |key, value| ENV.delete(key) if ENV[key] == value }
|
|
69
|
+
@mutations = {}
|
|
38
70
|
end
|
|
39
71
|
|
|
40
72
|
# Use this instead of getting values from `ENV` directly. It will throw an error if the requested value is missing or empty.
|
|
@@ -135,8 +167,10 @@ module Fastlane
|
|
|
135
167
|
default!.require_env_vars!(*keys)
|
|
136
168
|
end
|
|
137
169
|
|
|
138
|
-
# Clears the default instance, useful for test teardown.
|
|
170
|
+
# Clears the default instance, useful for test teardown. Also rolls back
|
|
171
|
+
# any `ENV` mutations the default instance performed via `mutate_env`.
|
|
139
172
|
def self.reset!
|
|
173
|
+
@default&.restore_env!
|
|
140
174
|
@default = nil
|
|
141
175
|
end
|
|
142
176
|
|
|
@@ -243,9 +243,11 @@ module Fastlane
|
|
|
243
243
|
# @param [Array<Hash{Symbol=>String}>] locales_map
|
|
244
244
|
# An array of locales to download. Each item in the array must be a Hash
|
|
245
245
|
# with keys `:glotpress` and `:android` containing the respective locale codes.
|
|
246
|
+
# @param [Boolean] fail_on_error Whether to fail on request errors or invalid downloaded XML.
|
|
246
247
|
#
|
|
247
|
-
def self.download_from_glotpress(res_dir:, glotpress_project_url:, locales_map:, glotpress_filters: { status: 'current' })
|
|
248
|
+
def self.download_from_glotpress(res_dir:, glotpress_project_url:, locales_map:, glotpress_filters: { status: 'current' }, fail_on_error: false)
|
|
248
249
|
glotpress_filters = [glotpress_filters] unless glotpress_filters.is_a?(Array)
|
|
250
|
+
UI.user_error!('At least one GlotPress filter is required.') if fail_on_error && glotpress_filters.empty?
|
|
249
251
|
|
|
250
252
|
orig_file = File.join(res_dir, 'values', 'strings.xml')
|
|
251
253
|
orig_xml = File.open(orig_file) { |f| Nokogiri::XML(f, nil, Encoding::UTF_8.to_s) }
|
|
@@ -253,7 +255,7 @@ module Fastlane
|
|
|
253
255
|
locales_map.each do |lang_codes|
|
|
254
256
|
all_xml_documents = glotpress_filters.map do |filters|
|
|
255
257
|
UI.message "Downloading translations for '#{lang_codes[:android]}' from GlotPress (#{lang_codes[:glotpress]}) [#{filters}]..."
|
|
256
|
-
download_glotpress_export_file(project_url: glotpress_project_url, locale: lang_codes[:glotpress], filters: filters)
|
|
258
|
+
download_glotpress_export_file(project_url: glotpress_project_url, locale: lang_codes[:glotpress], filters: filters, fail_on_error: fail_on_error)
|
|
257
259
|
end.compact
|
|
258
260
|
next if all_xml_documents.empty?
|
|
259
261
|
|
|
@@ -282,19 +284,35 @@ module Fastlane
|
|
|
282
284
|
# @param [String] locale The GlotPress locale code to download strings for.
|
|
283
285
|
# @param [Hash{Symbol=>String}] filters The hash of filters to apply when exporting from GlotPress.
|
|
284
286
|
# Typical examples include `{ status: 'current' }` or `{ status: 'review' }`.
|
|
287
|
+
# @param [Boolean] fail_on_error Whether to fail on request errors or invalid downloaded XML.
|
|
285
288
|
# @return [Nokogiri::XML::Document] the download XML document, parsed as a Nokogiri::XML object
|
|
286
289
|
#
|
|
287
|
-
def self.download_glotpress_export_file(project_url:, locale:, filters:)
|
|
290
|
+
def self.download_glotpress_export_file(project_url:, locale:, filters:, fail_on_error:)
|
|
288
291
|
query_params = filters.transform_keys { |k| "filters[#{k}]" }.merge(format: 'android')
|
|
289
292
|
url = "#{project_url.chomp('/')}/#{locale}/default/export-translations/?#{URI.encode_www_form(query_params)}"
|
|
290
293
|
|
|
291
294
|
Fastlane::Helper::GlotPressDownloader.download(
|
|
292
295
|
url: url,
|
|
293
296
|
locale: locale,
|
|
294
|
-
auto_retry: true
|
|
297
|
+
auto_retry: true,
|
|
298
|
+
fail_on_error: fail_on_error
|
|
295
299
|
) do |response_body|
|
|
296
300
|
# Replace tabs with spaces (GlotPress uses tabs, but we prefer spaces)
|
|
297
|
-
|
|
301
|
+
if fail_on_error
|
|
302
|
+
begin
|
|
303
|
+
xml = Nokogiri::XML(response_body.gsub("\t", ' '), nil, Encoding::UTF_8.to_s, &:strict)
|
|
304
|
+
rescue Nokogiri::XML::SyntaxError => e
|
|
305
|
+
UI.user_error!("Invalid Android translation export for locale `#{locale}` — #{e.message} (#{url})")
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
unless xml.root&.name == 'resources'
|
|
309
|
+
UI.user_error!("Invalid Android translation export for locale `#{locale}` — expected a `resources` root element (#{url})")
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
xml
|
|
313
|
+
else
|
|
314
|
+
Nokogiri::XML(response_body.gsub("\t", ' '), nil, Encoding::UTF_8.to_s)
|
|
315
|
+
end
|
|
298
316
|
end
|
|
299
317
|
end
|
|
300
318
|
private_class_method :download_glotpress_export_file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
module Helper
|
|
5
|
+
class ConfigItemHelper
|
|
6
|
+
def self.opt_in_fail_on_error_config_item
|
|
7
|
+
FastlaneCore::ConfigItem.new(
|
|
8
|
+
key: :fail_on_error,
|
|
9
|
+
description: 'Whether handled errors should fail the lane instead of using the action-specific fallback behavior',
|
|
10
|
+
type: FastlaneCore::Boolean,
|
|
11
|
+
optional: true,
|
|
12
|
+
default_value: false
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -9,19 +9,22 @@ module Fastlane
|
|
|
9
9
|
class GlotPressDownloader
|
|
10
10
|
AUTO_RETRY_SLEEP_TIME = 20
|
|
11
11
|
MAX_AUTO_RETRY_ATTEMPTS = 30
|
|
12
|
+
MAX_REDIRECTS = 10
|
|
12
13
|
|
|
13
|
-
attr_reader :auto_retry, :auto_retry_attempt_counter, :url, :locale
|
|
14
|
+
attr_reader :auto_retry, :auto_retry_attempt_counter, :url, :locale, :fail_on_error
|
|
14
15
|
|
|
15
16
|
# Initialize a new GlotPressDownloader
|
|
16
17
|
#
|
|
17
18
|
# @param [String] url The URL to download from
|
|
18
19
|
# @param [String] locale The locale being downloaded (for logging purposes)
|
|
19
20
|
# @param [Boolean] auto_retry Whether to automatically retry on rate limiting (429 errors)
|
|
21
|
+
# @param [Boolean] fail_on_error Whether to raise a Fastlane error after retry handling instead of returning false
|
|
20
22
|
#
|
|
21
|
-
def initialize(url:, locale:, auto_retry: false)
|
|
23
|
+
def initialize(url:, locale:, auto_retry: false, fail_on_error: false)
|
|
22
24
|
@url = url
|
|
23
25
|
@locale = locale
|
|
24
26
|
@auto_retry = auto_retry
|
|
27
|
+
@fail_on_error = fail_on_error
|
|
25
28
|
@auto_retry_attempt_counter = 0
|
|
26
29
|
end
|
|
27
30
|
|
|
@@ -30,34 +33,55 @@ module Fastlane
|
|
|
30
33
|
# @param [String] url The URL to download from
|
|
31
34
|
# @param [String] locale The locale being downloaded (for logging purposes)
|
|
32
35
|
# @param [Boolean] auto_retry Whether to automatically retry on rate limiting (429 errors)
|
|
33
|
-
# @
|
|
34
|
-
# @
|
|
36
|
+
# @param [Boolean] fail_on_error Whether to raise a Fastlane error after retry handling instead of returning false
|
|
37
|
+
# @yield [String] The response body if the download was successful. Return `false` to reject it and suppress the success message.
|
|
38
|
+
# @return The result of the block if provided, or true/false indicating success if no block is provided
|
|
39
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If the download fails after retry handling and `fail_on_error` is true
|
|
35
40
|
#
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
new(url: url, locale: locale, auto_retry: auto_retry).download(&)
|
|
41
|
+
def self.download(url:, locale:, auto_retry: false, fail_on_error: false, &)
|
|
42
|
+
new(url: url, locale: locale, auto_retry: auto_retry, fail_on_error: fail_on_error).download(&)
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
# Downloads data from GlotPress
|
|
42
46
|
#
|
|
43
|
-
# @yield [String] The response body if the download was successful
|
|
44
|
-
# @return The result of the block if provided, or true/false indicating success if no block provided
|
|
47
|
+
# @yield [String] The response body if the download was successful. Return `false` to reject it and suppress the success message.
|
|
48
|
+
# @return The result of the block if provided, or true/false indicating success if no block is provided
|
|
49
|
+
# @raise [FastlaneCore::Interface::FastlaneError] If the download fails after retry handling and `fail_on_error` is true
|
|
45
50
|
#
|
|
46
51
|
def download(&)
|
|
47
52
|
@auto_retry_attempt_counter = 0 # Reset counter only at start of download
|
|
48
|
-
download_from_url(@url, &)
|
|
53
|
+
download_from_url(@url, redirect_count: 0, &)
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
private
|
|
52
57
|
|
|
53
|
-
def download_from_url(url, &)
|
|
54
|
-
uri =
|
|
58
|
+
def download_from_url(url, redirect_count:, &)
|
|
59
|
+
uri = parse_uri(url)
|
|
60
|
+
return block_given? ? nil : false if uri.nil?
|
|
61
|
+
|
|
55
62
|
response = make_request(uri)
|
|
63
|
+
return block_given? ? nil : false if response.nil?
|
|
64
|
+
|
|
65
|
+
unless block_given?
|
|
66
|
+
return handle_response(response: response, url: url, original_uri: uri, redirect_count: redirect_count)
|
|
67
|
+
end
|
|
68
|
+
|
|
56
69
|
result = nil
|
|
57
|
-
|
|
58
|
-
result = yield
|
|
70
|
+
handle_response(response: response, url: url, original_uri: uri, redirect_count: redirect_count) do |body|
|
|
71
|
+
result = yield(body)
|
|
59
72
|
end
|
|
60
|
-
|
|
73
|
+
result
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def parse_uri(url)
|
|
77
|
+
uri = URI(url)
|
|
78
|
+
return uri if uri.is_a?(URI::HTTP) && uri.host
|
|
79
|
+
|
|
80
|
+
handle_failure("Invalid URL for locale `#{@locale}` (#{url})")
|
|
81
|
+
nil
|
|
82
|
+
rescue URI::InvalidURIError, TypeError => e
|
|
83
|
+
handle_failure("Invalid URL for locale `#{@locale}` — #{e.message} (#{url})")
|
|
84
|
+
nil
|
|
61
85
|
end
|
|
62
86
|
|
|
63
87
|
def make_request(uri)
|
|
@@ -68,60 +92,70 @@ module Fastlane
|
|
|
68
92
|
http.request(request)
|
|
69
93
|
rescue StandardError => e
|
|
70
94
|
# Network errors, connection errors, etc.
|
|
71
|
-
|
|
95
|
+
message = "Error downloading locale `#{@locale}` — #{e.message} (#{uri})"
|
|
72
96
|
retry if UI.interactive? && UI.confirm("Retry downloading `#{@locale}`?")
|
|
97
|
+
handle_failure(message)
|
|
73
98
|
nil
|
|
74
99
|
end
|
|
75
100
|
|
|
76
|
-
def handle_response(response:, url:, original_uri
|
|
77
|
-
return false if response.nil?
|
|
78
|
-
|
|
101
|
+
def handle_response(response:, url:, original_uri:, redirect_count:, &)
|
|
79
102
|
case response.code
|
|
80
103
|
when '200'
|
|
104
|
+
accepted = block_given? ? yield(response.body) : true
|
|
105
|
+
return false if accepted == false
|
|
106
|
+
|
|
81
107
|
UI.success("Successfully downloaded `#{@locale}`.")
|
|
82
|
-
yield response.body if block_given?
|
|
83
108
|
true
|
|
84
109
|
when '301', '302', '307', '308'
|
|
85
110
|
# Follow the redirect
|
|
86
111
|
UI.message("Received #{response.code} for `#{@locale}`. Following redirect...")
|
|
87
112
|
redirect_url = response['location']
|
|
88
|
-
if redirect_url.nil?
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
113
|
+
return handle_failure("Received #{response.code} for `#{@locale}` but no location header was found (#{original_uri}).") if redirect_url.nil? || redirect_url.empty?
|
|
114
|
+
return handle_failure("Too many redirects while downloading locale `#{@locale}` (#{original_uri}).") if redirect_count >= MAX_REDIRECTS
|
|
115
|
+
|
|
116
|
+
resolved_url = resolve_redirect_url(original_uri, redirect_url)
|
|
117
|
+
return false if resolved_url.nil?
|
|
118
|
+
|
|
119
|
+
download_from_url(resolved_url, redirect_count: redirect_count + 1, &)
|
|
95
120
|
when '429'
|
|
96
121
|
# Rate limited
|
|
97
|
-
handle_rate_limiting(url: url
|
|
98
|
-
yield body if block_given?
|
|
99
|
-
end
|
|
122
|
+
handle_rate_limiting(url: url, response: response, redirect_count: redirect_count, &)
|
|
100
123
|
else
|
|
101
124
|
# Unexpected status code (including 404, 500, etc.)
|
|
102
|
-
status_line =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
false
|
|
108
|
-
end
|
|
125
|
+
status_line = [response.code, response.message].compact.join(' ').strip
|
|
126
|
+
message = "Error downloading locale `#{@locale}` — #{status_line} (#{original_uri})"
|
|
127
|
+
return handle_failure(message) unless UI.interactive? && UI.confirm("Retry downloading `#{@locale}`?")
|
|
128
|
+
|
|
129
|
+
download_from_url(url, redirect_count: redirect_count, &)
|
|
109
130
|
end
|
|
110
131
|
end
|
|
111
132
|
|
|
112
|
-
def handle_rate_limiting(url
|
|
133
|
+
def handle_rate_limiting(url:, response:, redirect_count:, &)
|
|
113
134
|
if @auto_retry && @auto_retry_attempt_counter < MAX_AUTO_RETRY_ATTEMPTS
|
|
114
135
|
UI.message("Received 429 for `#{@locale}`. Auto retrying in #{AUTO_RETRY_SLEEP_TIME} seconds... (attempt #{@auto_retry_attempt_counter + 1}/#{MAX_AUTO_RETRY_ATTEMPTS})")
|
|
115
136
|
sleep(AUTO_RETRY_SLEEP_TIME)
|
|
116
137
|
@auto_retry_attempt_counter += 1
|
|
117
|
-
download_from_url(url
|
|
138
|
+
download_from_url(url, redirect_count: redirect_count, &)
|
|
118
139
|
elsif UI.interactive? && UI.confirm("Retry downloading `#{@locale}` after receiving 429 from the API?")
|
|
119
|
-
download_from_url(url
|
|
140
|
+
download_from_url(url, redirect_count: redirect_count, &)
|
|
120
141
|
else
|
|
121
|
-
|
|
122
|
-
|
|
142
|
+
status_line = [response.code, response.message].compact.join(' ').strip
|
|
143
|
+
handle_failure("Error downloading locale `#{@locale}` — #{status_line} (#{url})")
|
|
123
144
|
end
|
|
124
145
|
end
|
|
146
|
+
|
|
147
|
+
def resolve_redirect_url(original_uri, redirect_url)
|
|
148
|
+
URI.join(original_uri.to_s, redirect_url).to_s
|
|
149
|
+
rescue URI::InvalidURIError => e
|
|
150
|
+
handle_failure("Invalid redirect URL for locale `#{@locale}` — #{e.message} (#{redirect_url})")
|
|
151
|
+
nil
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def handle_failure(message)
|
|
155
|
+
UI.error(message)
|
|
156
|
+
UI.user_error!(message) if @fail_on_error
|
|
157
|
+
false
|
|
158
|
+
end
|
|
125
159
|
end
|
|
126
160
|
end
|
|
127
161
|
end
|
|
@@ -191,26 +191,27 @@ module Fastlane
|
|
|
191
191
|
# @param [Hash{Symbol=>String}] filters The hash of filters to apply when exporting from GlotPress.
|
|
192
192
|
# Typical examples include `{ status: 'current' }` or `{ status: 'review' }`.
|
|
193
193
|
# @param [String, IO] destination The path or `IO`-like instance, where to write the downloaded file on disk.
|
|
194
|
+
# @param [Boolean] fail_on_error Whether to fail on request errors.
|
|
194
195
|
#
|
|
195
|
-
def self.download_glotpress_export_file(project_url:, locale:, filters:, destination:)
|
|
196
|
+
def self.download_glotpress_export_file(project_url:, locale:, filters:, destination:, fail_on_error: false)
|
|
196
197
|
query_params = (filters || {}).transform_keys { |k| "filters[#{k}]" }.merge(format: 'strings')
|
|
197
198
|
url = "#{project_url.chomp('/')}/#{locale}/default/export-translations/?#{URI.encode_www_form(query_params)}"
|
|
198
199
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
end
|
|
200
|
+
Fastlane::Helper::GlotPressDownloader.download(
|
|
201
|
+
url: url,
|
|
202
|
+
locale: locale,
|
|
203
|
+
auto_retry: true,
|
|
204
|
+
fail_on_error: fail_on_error
|
|
205
|
+
) do |response_body|
|
|
206
|
+
if destination.is_a?(String)
|
|
207
|
+
File.write(destination, response_body)
|
|
208
|
+
else
|
|
209
|
+
destination.write(response_body)
|
|
210
210
|
end
|
|
211
211
|
rescue StandardError => e
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
message = "Error writing downloaded locale `#{locale}` — #{e.message} (#{url})"
|
|
213
|
+
fail_on_error ? UI.user_error!(message) : UI.error(message)
|
|
214
|
+
false
|
|
214
215
|
end
|
|
215
216
|
end
|
|
216
217
|
end
|
|
@@ -9,10 +9,11 @@ module Fastlane
|
|
|
9
9
|
class MetadataDownloader
|
|
10
10
|
attr_reader :target_folder, :target_files
|
|
11
11
|
|
|
12
|
-
def initialize(target_folder, target_files, auto_retry)
|
|
12
|
+
def initialize(target_folder, target_files, auto_retry, fail_on_error: false)
|
|
13
13
|
@target_folder = target_folder
|
|
14
14
|
@target_files = target_files
|
|
15
15
|
@auto_retry = auto_retry
|
|
16
|
+
@fail_on_error = fail_on_error
|
|
16
17
|
@alternates = {}
|
|
17
18
|
end
|
|
18
19
|
|
|
@@ -21,9 +22,10 @@ module Fastlane
|
|
|
21
22
|
GlotPressDownloader.download(
|
|
22
23
|
url: glotpress_url,
|
|
23
24
|
locale: target_locale,
|
|
24
|
-
auto_retry: @auto_retry
|
|
25
|
+
auto_retry: @auto_retry,
|
|
26
|
+
fail_on_error: @fail_on_error
|
|
25
27
|
) do |response_body|
|
|
26
|
-
handle_glotpress_response(response_body: response_body, locale: target_locale, is_source: is_source)
|
|
28
|
+
handle_glotpress_response(response_body: response_body, locale: target_locale, is_source: is_source, url: glotpress_url)
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
|
|
@@ -106,17 +108,34 @@ module Fastlane
|
|
|
106
108
|
|
|
107
109
|
private
|
|
108
110
|
|
|
109
|
-
def handle_glotpress_response(response_body:, locale:, is_source:)
|
|
111
|
+
def handle_glotpress_response(response_body:, locale:, is_source:, url:)
|
|
110
112
|
# Parse the JSON response
|
|
111
113
|
@alternates.clear
|
|
112
|
-
loc_data =
|
|
113
|
-
|
|
114
|
-
rescue StandardError
|
|
115
|
-
nil
|
|
116
|
-
end
|
|
114
|
+
loc_data = parse_metadata_response(response_body: response_body, locale: locale, url: url)
|
|
115
|
+
|
|
117
116
|
parse_data(locale, loc_data, is_source)
|
|
118
117
|
reparse_alternates(locale, loc_data, is_source) unless @alternates.empty?
|
|
119
118
|
end
|
|
119
|
+
|
|
120
|
+
def parse_metadata_response(response_body:, locale:, url:)
|
|
121
|
+
return JSON.parse(response_body) unless @fail_on_error
|
|
122
|
+
|
|
123
|
+
loc_data = JSON.parse(response_body)
|
|
124
|
+
UI.user_error!("Unexpected GlotPress metadata response for locale `#{locale}` (#{url})") unless valid_metadata_response?(loc_data)
|
|
125
|
+
loc_data
|
|
126
|
+
rescue JSON::ParserError, TypeError => e
|
|
127
|
+
UI.user_error!("Error parsing GlotPress response for locale `#{locale}` — #{e.message} (#{url})") if @fail_on_error
|
|
128
|
+
nil
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def valid_metadata_response?(loc_data)
|
|
132
|
+
return loc_data.empty? if loc_data.is_a?(Array)
|
|
133
|
+
return false unless loc_data.is_a?(Hash) && !loc_data.empty?
|
|
134
|
+
|
|
135
|
+
loc_data.all? do |source, translations|
|
|
136
|
+
source.is_a?(String) && translations.is_a?(Array) && translations.all?(String)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
120
139
|
end
|
|
121
140
|
end
|
|
122
141
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fastlane-plugin-wpmreleasetoolkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 15.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Automattic
|
|
@@ -71,14 +71,14 @@ dependencies:
|
|
|
71
71
|
requirements:
|
|
72
72
|
- - "~>"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: '2.
|
|
74
|
+
version: '2.240'
|
|
75
75
|
type: :runtime
|
|
76
76
|
prerelease: false
|
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
79
|
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: '2.
|
|
81
|
+
version: '2.240'
|
|
82
82
|
- !ruby/object:Gem::Dependency
|
|
83
83
|
name: gettext
|
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -271,7 +271,6 @@ files:
|
|
|
271
271
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/android/an_localize_libs_action.rb
|
|
272
272
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/android/an_update_metadata_source_action.rb
|
|
273
273
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/android/an_validate_lib_strings_action.rb
|
|
274
|
-
- lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_build_preflight.rb
|
|
275
274
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_create_avd_action.rb
|
|
276
275
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_create_xml_release_notes.rb
|
|
277
276
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_current_branch_is_hotfix.rb
|
|
@@ -324,7 +323,6 @@ files:
|
|
|
324
323
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/configure/configure_validate_action.rb
|
|
325
324
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/add_development_certificates_to_provisioning_profiles.rb
|
|
326
325
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/add_devices_to_provisioning_profiles.rb
|
|
327
|
-
- lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_build_preflight.rb
|
|
328
326
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_check_beta_deps.rb
|
|
329
327
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_download_strings_files_from_glotpress.rb
|
|
330
328
|
- lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_extract_keys_from_strings_files.rb
|
|
@@ -345,6 +343,7 @@ files:
|
|
|
345
343
|
- lib/fastlane/plugin/wpmreleasetoolkit/helper/apps_cdn_helper.rb
|
|
346
344
|
- lib/fastlane/plugin/wpmreleasetoolkit/helper/buildkite_aware_log_groups.rb
|
|
347
345
|
- lib/fastlane/plugin/wpmreleasetoolkit/helper/ci_helper.rb
|
|
346
|
+
- lib/fastlane/plugin/wpmreleasetoolkit/helper/config_item_helper.rb
|
|
348
347
|
- lib/fastlane/plugin/wpmreleasetoolkit/helper/configure_helper.rb
|
|
349
348
|
- lib/fastlane/plugin/wpmreleasetoolkit/helper/encryption_helper.rb
|
|
350
349
|
- lib/fastlane/plugin/wpmreleasetoolkit/helper/filesystem_helper.rb
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fastlane
|
|
4
|
-
module Actions
|
|
5
|
-
class AndroidBuildPreflightAction < Action
|
|
6
|
-
def self.run(params)
|
|
7
|
-
# Validate mobile configuration secrets
|
|
8
|
-
other_action.configure_apply
|
|
9
|
-
|
|
10
|
-
# Check gems and pods are up to date. This will exit if it fails
|
|
11
|
-
begin
|
|
12
|
-
Action.sh('bundle check')
|
|
13
|
-
rescue StandardError
|
|
14
|
-
UI.user_error!("You should run 'bundle install' to make sure gems are up to date")
|
|
15
|
-
raise
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
begin
|
|
19
|
-
Action.sh('command -v bundletool > /dev/null')
|
|
20
|
-
rescue StandardError
|
|
21
|
-
UI.user_error!("bundletool is required to build the APKs. Install it with 'brew install bundletool'")
|
|
22
|
-
raise
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
#####################################################
|
|
27
|
-
# @!group Documentation
|
|
28
|
-
#####################################################
|
|
29
|
-
|
|
30
|
-
def self.description
|
|
31
|
-
'Clean the environment to ensure a safe build'
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def self.details
|
|
35
|
-
'Clean the environment to ensure a safe build'
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def self.available_options
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def self.output
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def self.return_value
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def self.authors
|
|
48
|
-
['Automattic']
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def self.is_supported?(platform)
|
|
52
|
-
platform == :android
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fastlane
|
|
4
|
-
module Actions
|
|
5
|
-
class IosBuildPreflightAction < Action
|
|
6
|
-
def self.run(params)
|
|
7
|
-
# Validate mobile configuration secrets
|
|
8
|
-
other_action.configure_apply
|
|
9
|
-
|
|
10
|
-
Action.sh("cd .. && rm -rf #{params[:derived_data_path]}")
|
|
11
|
-
|
|
12
|
-
# Verify that ImageMagick exists on this machine and can be called from the command-line.
|
|
13
|
-
# Internal Builds use it to generate the App Icon as part of the build process
|
|
14
|
-
begin
|
|
15
|
-
Action.sh('which convert')
|
|
16
|
-
rescue StandardError
|
|
17
|
-
UI.user_error!("Couldn't find ImageMagick. Please install it by running `brew install imagemagick`")
|
|
18
|
-
raise
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Verify that Ghostscript exists on this machine and can be called from the command-line.
|
|
22
|
-
# Internal Builds use it to generate the App Icon as part of the build process
|
|
23
|
-
begin
|
|
24
|
-
Action.sh('which gs')
|
|
25
|
-
rescue StandardError
|
|
26
|
-
UI.user_error!("Couldn't find Ghostscript. Please install it by running `brew install ghostscript`")
|
|
27
|
-
raise
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Check gems and pods are up to date. This will exit if it fails
|
|
31
|
-
begin
|
|
32
|
-
Action.sh('bundle check')
|
|
33
|
-
rescue StandardError
|
|
34
|
-
UI.user_error!("You should run 'rake dependencies' to make sure gems are up to date")
|
|
35
|
-
raise
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
other_action.cocoapods
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
#####################################################
|
|
42
|
-
# @!group Documentation
|
|
43
|
-
#####################################################
|
|
44
|
-
|
|
45
|
-
def self.description
|
|
46
|
-
'Clean the environment to ensure a safe build'
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def self.details
|
|
50
|
-
'Clean the environment to ensure a safe build'
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def self.available_options
|
|
54
|
-
[
|
|
55
|
-
FastlaneCore::ConfigItem.new(
|
|
56
|
-
key: :derived_data_path,
|
|
57
|
-
description: "The path to the DerivedData directory for the project. Should match what's used in the `gym` action",
|
|
58
|
-
type: String,
|
|
59
|
-
default_value: '~/Library/Developer/Xcode/DerivedData'
|
|
60
|
-
),
|
|
61
|
-
]
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def self.output
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def self.return_value
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def self.authors
|
|
71
|
-
['Automattic']
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def self.is_supported?(platform)
|
|
75
|
-
%i[ios mac].include?(platform)
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|