fastlane-plugin-flutter 0.2.7 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fb29c8dc7585bdd45029e7c2718a113a6d47598c
4
- data.tar.gz: a21b6f7c0ef29dca72423d6f6fcb638989cb0321
3
+ metadata.gz: 3e378c20ed4cdebc4af0d1034b9a33c1c6836ad8
4
+ data.tar.gz: 722fa1646960e5838262036a875206bb404543d8
5
5
  SHA512:
6
- metadata.gz: a9b569b2f6e8fb92c5751886e8f3ed44d3ccb1cb2e0157a97accb22fa0fa4b59588afd07469fbeefad46e603c062eab80328a7f368ad27c89faa9636a1b2c90a
7
- data.tar.gz: eb9887fda61f9518021b2ca43bdbc09400c996465dd5ba9971596b9aa3667dccebf344ccf49e5c5115f50ebd396fcb0bb3a9032e8bf7e2004bb717dbaa6053c3
6
+ metadata.gz: 53db9cf6533fc97b1b5ae367764dffeddcb6bccca320e3fe70214e88c4b90f99fdd2834ccad6d8e7797fc6a02c9ecd4df292ee92f5e19987bfa925be7ac6f406
7
+ data.tar.gz: 5e0387e7c92ffe9d36ba25f26daa9dab60ab25eab9f9a0f0403fe1baa91b875c783b87fdbf86f6db1c91a3f570c8f819b92b3800b2d4edab779397810ac53491
data/README.md CHANGED
@@ -6,8 +6,8 @@
6
6
 
7
7
  This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-flutter`, add it to your project by running:
8
8
 
9
- ```bash
10
- fastlane add_plugin flutter
9
+ ```shell
10
+ $ fastlane add_plugin flutter
11
11
  ```
12
12
 
13
13
  ## About flutter
@@ -16,21 +16,23 @@ Flutter actions plugin for Fastlane.
16
16
 
17
17
  ## Example
18
18
 
19
- Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
20
-
21
- **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
19
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin.
22
20
 
23
21
  ## Run tests for this plugin
24
22
 
25
23
  To run both the tests, and code style validation, run
26
24
 
27
- ```
28
- rake
25
+ ```shell
26
+ $ bundle install
27
+ $ bundle exec rake
28
+ $ bundle exec fastlane end_to_end_test
29
29
  ```
30
30
 
31
31
  To automatically fix many of the styling issues, use
32
- ```
33
- rubocop -a
32
+
33
+ ```shell
34
+ $ bundle install
35
+ $ bundle exec rubocop -a
34
36
  ```
35
37
 
36
38
  ## Issues and Feedback
@@ -1,313 +1,30 @@
1
1
  require 'fastlane/action'
2
+ require_relative '../base/flutter_action_base'
2
3
  require_relative '../helper/flutter_helper'
3
4
 
4
- # This is the entry point for this plugin. For more information on writing
5
- # plugins: https://docs.fastlane.tools/advanced/
6
-
7
5
  module Fastlane
8
6
  module Actions
9
- module SharedValues
10
- FLUTTER_OUTPUT_APP = :FLUTTER_OUTPUT_APP
11
- FLUTTER_OUTPUT_APK = :FLUTTER_OUTPUT_APK
12
- FLUTTER_OUTPUT_BUILD_NUMBER_OVERRIDE =
13
- :FLUTTER_OUTPUT_BUILD_NUMBER_OVERRIDE
14
- FLUTTER_OUTPUT_BUILD_NAME_OVERRIDE = :FLUTTER_OUTPUT_BUILD_NAME_OVERRIDE
15
- end
16
-
17
7
  class FlutterAction < Action
18
- FLUTTER_ACTIONS = %w(build analyze test format l10n bootstrap)
19
-
20
- PLATFORM_TO_FLUTTER = {
21
- ios: 'ios',
22
- android: 'apk',
23
- }
24
-
25
- PLATFORM_TO_OUTPUT = {
26
- ios: SharedValues::FLUTTER_OUTPUT_APP,
27
- android: SharedValues::FLUTTER_OUTPUT_APK,
28
- }
8
+ extend FlutterActionBase
29
9
 
30
10
  def self.run(params)
31
- # You can print a table of plugin configuration params like that:
32
- #
33
- # FastlaneCore::PrintTable.print_values(
34
- # config: params,
35
- # title: "Summary for Flutter plugin #{Fastlane::Flutter::VERSION}",
36
- # )
37
-
38
- case params[:action]
39
- when 'build'
40
- # A map of fastlane platform name into "flutter build" args list.
41
- build_args = {}
42
-
43
- if lane_context.key?(SharedValues::PLATFORM_NAME)
44
- fastlane_platform = lane_context[SharedValues::PLATFORM_NAME]
45
- build_args[fastlane_platform] =
46
- [PLATFORM_TO_FLUTTER[fastlane_platform]]
47
- else
48
- # If platform is unspecified, build for all platforms.
49
- PLATFORM_TO_FLUTTER.each_key do |platform|
50
- build_args[platform] = [PLATFORM_TO_FLUTTER[platform]]
51
- end
52
- end
53
-
54
- if params[:debug]
55
- build_args.each_value do |a|
56
- a.push('--debug')
57
- end
58
- end
59
-
60
- unless params[:codesign]
61
- build_args[:ios].push('--no-codesign') if build_args.key?(:ios)
62
- end
63
-
64
- if lane_context[SharedValues::FLUTTER_OUTPUT_BUILD_NUMBER_OVERRIDE] =
65
- build_number = Helper::FlutterHelper.build_number(
66
- params[:build_number_override]
67
- )
68
- build_args.each_value do |a|
69
- a.push('--build-number', build_number.to_s)
70
- end
71
- end
72
-
73
- if lane_context[SharedValues::FLUTTER_OUTPUT_BUILD_NAME_OVERRIDE] =
74
- build_name = Helper::FlutterHelper.build_name(
75
- params[:build_name_override]
76
- )
77
- build_args.each_value do |a|
78
- a.push('--build-name', build_name)
79
- end
80
- end
81
-
82
- # Note: this statement is expected to return a value (map of platform
83
- # into file name).
84
- Hash[build_args.keys.zip(build_args.map do |platform, args|
85
- sh('flutter', 'build', *args) do |status, res|
86
- if status.success?
87
- # Dirty hacks ahead!
88
- if PLATFORM_TO_OUTPUT.key?(platform)
89
- if res =~ /^Built (.*?)(:? \([^)]*\))?\.$/
90
- lane_context[PLATFORM_TO_OUTPUT[platform]] =
91
- File.absolute_path($1)
92
- end
93
- end
94
- else
95
- # fastlane does not fail automatically if we provide a block.
96
- UI.build_failure!("flutter build #{platform} has failed.")
97
- end
98
- end
99
- end.compact)]
100
- when 'test'
101
- sh *%w(flutter test)
102
- when 'analyze'
103
- sh *%w(flutter analyze)
104
- when 'format'
105
- sh *%w(flutter format .)
106
- when 'l10n'
107
- run_l10n(params)
108
- when 'bootstrap'
109
- Helper::FlutterHelper.bootstrap_android(params[:android_licenses])
110
- end
111
- end
112
-
113
- def self.run_l10n(params)
114
- unless params[:l10n_strings_file]
115
- UI.user_error!('l10n_strings_file is a required parameter for ' \
116
- 'l10n action')
117
- end
118
-
119
- output_dir = 'lib/l10n'
120
- l10n_messages_file = File.join(output_dir, 'intl_messages.arb')
121
- # This file will not exist before it's generated for the first time.
122
- if File.exist?(l10n_messages_file)
123
- l10n_messages_was = File.read(l10n_messages_file)
124
- end
125
-
126
- extract_to_arb_options = ["--output-dir=#{output_dir}"]
127
- if params[:l10n_strings_locale]
128
- extract_to_arb_options.push(
129
- "--locale=#{params[:l10n_strings_locale]}"
130
- )
131
- end
132
-
133
- sh *%w(flutter packages pub run intl_translation:extract_to_arb),
134
- *extract_to_arb_options, params[:l10n_strings_file]
135
-
136
- if l10n_messages_was
137
- # intl will update @@last_modified even if there are no updates;
138
- # this leaves Git directory unnecessary dirty. If that's the only
139
- # change, just restore the previous contents.
140
- if Helper::FlutterHelper.restore_l10n_timestamp(
141
- l10n_messages_file, l10n_messages_was
142
- )
143
- UI.message(
144
- "@@last_modified has been restored in #{l10n_messages_file}"
145
- )
146
- end
147
- end
148
-
149
- # Sort files for consistency, because messages_all.dart will have
150
- # imports ordered as in the command line below.
151
- arb_files = Dir.glob(File.join(output_dir, 'intl_*.arb')).sort
152
-
153
- if params[:l10n_verify_arb]
154
- errors_found = arb_files.any? do |arb_file|
155
- unless arb_file == l10n_messages_file
156
- UI.message("Verifying #{arb_file}...")
157
- errors = Helper::FlutterHelper.compare_arb(l10n_messages_file,
158
- arb_file)
159
- if errors.any?
160
- errors.each { |e| UI.error(e) }
161
- end
162
- end
163
- end
164
- UI.user_error!('Found inconsistencies in ARB files') if errors_found
165
- end
166
-
167
- unless params[:l10n_strings_locale]
168
- # Don't generate .dart for the original ARB unless it has its own
169
- # locale.
170
- arb_files.delete(l10n_messages_file)
171
- end
172
-
173
- if params[:l10n_reformat_arb]
174
- arb_files.each do |arb_file|
175
- UI.message("Reformatting file #{arb_file}...")
176
- Helper::FlutterHelper.reformat_arb(arb_file)
177
- end
178
- end
179
-
180
- sh *%W(flutter packages pub run intl_translation:generate_from_arb
181
- --output-dir=#{output_dir}
182
- --no-use-deferred-loading
183
- #{params[:l10n_strings_file]}) + arb_files
11
+ Helper::FlutterHelper.flutter(*params[:args])
184
12
  end
185
13
 
186
14
  def self.description
187
- "Flutter actions plugin for Fastlane"
188
- end
189
-
190
- def self.authors
191
- ["Artem Sheremet"]
192
- end
193
-
194
- def self.return_value
195
- 'For "build" action, the return value is a mapping of fastlane ' \
196
- 'platform names into built output files, e.g.: ' +
197
- { android: '/Users/foo/src/flutter/build/outputs/myapp.apk' }.inspect
198
- end
199
-
200
- def self.details
201
- # Optional:
202
- ""
15
+ 'Run "flutter" binary with the specified arguments'
203
16
  end
204
17
 
205
18
  def self.available_options
206
19
  [
207
20
  FastlaneCore::ConfigItem.new(
208
- key: :action,
209
- env_name: 'FL_FLUTTER_ACTION',
210
- description: 'Flutter action to run',
211
- optional: false,
212
- type: String,
213
- verify_block: proc do |value|
214
- unless FLUTTER_ACTIONS.include?(value)
215
- UI.user_error!("Supported actions are: #{FLUTTER_ACTIONS}")
216
- end
217
- end,
218
- ),
219
- FastlaneCore::ConfigItem.new(
220
- key: :debug,
221
- env_name: 'FL_FLUTTER_DEBUG',
222
- description: 'Build a Debug version of the app if true',
223
- optional: true,
224
- is_string: false,
225
- default_value: false,
226
- ),
227
- FastlaneCore::ConfigItem.new(
228
- key: :codesign,
229
- env_name: 'FL_FLUTTER_CODESIGN',
230
- description: 'Set to false to skip iOS app signing. This may be ' \
231
- 'useful e.g. on CI or when signed by Fastlane "sigh"',
232
- optional: true,
233
- is_string: false,
234
- default_value: true,
235
- ),
236
- FastlaneCore::ConfigItem.new(
237
- key: :build_number_override,
238
- env_name: 'FL_FLUTTER_BUILD_NUMBER_OVERRIDE',
239
- description: <<-'DESCRIPTION',
240
- Override build number in pubspec.yaml. Can be either a number, or
241
- a schema definition, ex.: ci (take from CI) vcs (take from Git),
242
- ci+1000 (take from CI and add 1000).
243
- DESCRIPTION
244
- optional: true,
245
- verify_block: Helper::FlutterHelper.method(:build_number),
246
- ),
247
- FastlaneCore::ConfigItem.new(
248
- key: :build_name_override,
249
- env_name: 'FL_FLUTTER_BUILD_NAME_OVERRIDE',
250
- description: <<-'DESCRIPTION',
251
- Override build name in pubspec.yaml. Can be either a string, or a
252
- schema definition, ex.: vcs* (take from VCS, add "*" for dirty
253
- tree), vcs (take from VCS, no dirty mark), ^vcs (take from the
254
- latest VCS tag which must be in the form X.Y, and add the number
255
- of commits since that tag as the third number, unless it's zero).
256
- NOTE: for App Store, build name must be in the format of at most 3
257
- integeres separated by a dot (".").
258
- DESCRIPTION
259
- optional: true,
260
- verify_block: Helper::FlutterHelper.method(:build_name),
261
- ),
262
- # l10n settings
263
- FastlaneCore::ConfigItem.new(
264
- key: :l10n_strings_file,
265
- env_name: 'FL_FLUTTER_L10N_STRINGS',
266
- description: 'Path to the .dart file with l10n strings',
267
- optional: true,
268
- verify_block: proc do |value|
269
- UI.user_error!('File does not exist') unless File.exist?(value)
270
- end,
271
- ),
272
- FastlaneCore::ConfigItem.new(
273
- key: :l10n_strings_locale,
274
- env_name: 'FL_FLUTTER_L10N_STRINGS_LOCALE',
275
- description: 'Locale of the data in l10n_strings_file',
276
- optional: true,
277
- ),
278
- FastlaneCore::ConfigItem.new(
279
- key: :l10n_reformat_arb,
280
- env_name: 'FL_FLUTTER_L10N_REFORMAT_ARB',
281
- description: 'Reformat .arb files',
282
- optional: true,
283
- is_string: false,
284
- default_value: false,
285
- ),
286
- FastlaneCore::ConfigItem.new(
287
- key: :l10n_verify_arb,
288
- env_name: 'FL_FLUTTER_L10N_VERIFY_ARB',
289
- description: 'Verify that each .arb file includes all strings',
290
- optional: true,
291
- is_string: false,
292
- default_value: true,
293
- ),
294
- FastlaneCore::ConfigItem.new(
295
- key: :android_licenses,
296
- env_name: 'FL_FLUTTER_ANDROID_LICENSES',
297
- description: 'Hashes of accepted Android SDK linceses, which may ' \
298
- 'be found in $ANDROID_SDK_ROOT/licenses',
299
- optional: true,
300
- is_string: false,
301
- verify_block: proc { |value| value.kind_of?(Hash) },
302
- default_value: {},
21
+ key: :args,
22
+ env_name: 'FL_FLUTTER_ARGS',
23
+ description: 'Arguments to Flutter command',
24
+ type: Array,
303
25
  ),
304
26
  ]
305
27
  end
306
-
307
- def self.is_supported?(platform)
308
- # Also support nil (root lane).
309
- [nil, :ios, :android].include?(platform)
310
- end
311
28
  end
312
29
  end
313
30
  end
@@ -0,0 +1,80 @@
1
+ require 'fastlane/action'
2
+ require_relative '../base/flutter_action_base'
3
+ require_relative '../helper/flutter_helper'
4
+ require_relative '../helper/flutter_bootstrap_helper'
5
+
6
+ module Fastlane
7
+ module Actions
8
+ class FlutterBootstrapAction < Action
9
+ extend FlutterActionBase
10
+
11
+ def self.run(params)
12
+ if params[:android_licenses]
13
+ Helper::FlutterBootstrapHelper.accept_licenses(
14
+ File.join(android_sdk_root!, 'licenses'),
15
+ params[:android_licenses],
16
+ )
17
+ end
18
+
19
+ # Upgrade or install Flutter SDK.
20
+ flutter_sdk_root = Helper::FlutterHelper.flutter_sdk_root
21
+ flutter_channel = params[:flutter_channel]
22
+ if File.directory?(flutter_sdk_root)
23
+ UI.message("Upgrading Flutter SDK in #{flutter_sdk_root}...")
24
+ if flutter_channel
25
+ UI.message("Making sure Flutter is on channel #{flutter_channel}")
26
+ Helper::FlutterHelper.flutter(
27
+ 'channel', flutter_channel, log: false
28
+ )
29
+ end
30
+ Helper::FlutterHelper.flutter('upgrade', log: false)
31
+ else
32
+ Helper::FlutterHelper.git(
33
+ 'clone', # no --depth to keep Flutter tag-based versioning.
34
+ "--branch=#{flutter_channel || 'beta'}",
35
+ '--',
36
+ 'https://github.com/flutter/flutter.git',
37
+ flutter_sdk_root,
38
+ )
39
+ end
40
+ UI.message('Precaching Flutter SDK binaries...')
41
+ Helper::FlutterHelper.flutter('precache', log: false)
42
+ end
43
+
44
+ def self.android_sdk_root!
45
+ (ENV['ANDROID_HOME'] || ENV['ANDROID_SDK_ROOT']).tap do |path|
46
+ unless path
47
+ UI.build_failure!('Android SDK directory environment variables ' \
48
+ 'are not set. See ' \
49
+ 'https://developer.android.com/studio/command-line/variables')
50
+ end
51
+ end
52
+ end
53
+
54
+ def self.description
55
+ 'Flutter SDK installation, upgrade and application bootstrap'
56
+ end
57
+
58
+ def self.available_options
59
+ [
60
+ FastlaneCore::ConfigItem.new(
61
+ key: :flutter_channel,
62
+ env_name: 'FL_FLUTTER_CHANNEL',
63
+ description: 'Flutter SDK channel (keep existing if unset)',
64
+ optional: true,
65
+ type: String,
66
+ ),
67
+ FastlaneCore::ConfigItem.new(
68
+ key: :android_licenses,
69
+ description: 'Map of file names to hash values of accepted ' \
70
+ 'Android SDK linceses, which may be found in ' \
71
+ '$ANDROID_SDK_ROOT/licenses/ on developer workstations. Gradle ' \
72
+ 'will refuse to install SDK unless licenses are accepted',
73
+ optional: true,
74
+ type: Hash,
75
+ ),
76
+ ]
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,124 @@
1
+ require 'fastlane/action'
2
+ require_relative '../base/flutter_action_base'
3
+ require_relative '../helper/flutter_helper'
4
+
5
+ module Fastlane
6
+ module Actions
7
+ module SharedValues
8
+ FLUTTER_OUTPUT = :FLUTTER_OUTPUT
9
+ end
10
+
11
+ class FlutterBuildAction < Action
12
+ extend FlutterActionBase
13
+
14
+ FASTLANE_PLATFORM_TO_BUILD = {
15
+ ios: 'ios',
16
+ android: 'apk',
17
+ }
18
+
19
+ def self.run(params)
20
+ # "flutter build" args list.
21
+ build_args = []
22
+
23
+ if params[:build]
24
+ build_args.push(params[:build])
25
+ else
26
+ if fastlane_platform = (lane_context[SharedValues::PLATFORM_NAME] ||
27
+ lane_context[SharedValues::DEFAULT_PLATFORM])
28
+ build_args.push(FASTLANE_PLATFORM_TO_BUILD[fastlane_platform])
29
+ else
30
+ UI.user_error!('flutter_build action "build" parameter is not ' \
31
+ 'specified and cannot be inferred from Fastlane context.')
32
+ end
33
+ end
34
+
35
+ if params[:debug]
36
+ build_args.push('--debug')
37
+ end
38
+
39
+ if params[:codesign] == false
40
+ build_args.push('--no-codesign')
41
+ end
42
+
43
+ if build_number = (params[:build_number] ||
44
+ lane_context[SharedValues::BUILD_NUMBER])
45
+ build_args.push('--build-number', build_number.to_s)
46
+ end
47
+
48
+ if build_name = (params[:build_name] ||
49
+ lane_context[SharedValues::VERSION_NUMBER])
50
+ build_args.push('--build-name', build_name.to_s)
51
+ end
52
+
53
+ Helper::FlutterHelper.flutter('build', *build_args) do |status, res|
54
+ if status.success?
55
+ if res =~ /^Built (.*?)(:? \([^)]*\))?\.$/
56
+ lane_context[SharedValues::FLUTTER_OUTPUT] =
57
+ File.absolute_path($1)
58
+ else
59
+ UI.important('Cannot parse built file path from "flutter build"')
60
+ end
61
+ else
62
+ # fastlane does not fail automatically if we provide a block.
63
+ UI.build_failure!('"flutter build" has failed')
64
+ end
65
+ end
66
+
67
+ lane_context[SharedValues::FLUTTER_OUTPUT]
68
+ end
69
+
70
+ def self.description
71
+ 'Run "flutter build" to build a Flutter application'
72
+ end
73
+
74
+ def self.return_value
75
+ 'A path to the built file, if available'
76
+ end
77
+
78
+ def self.available_options
79
+ [
80
+ FastlaneCore::ConfigItem.new(
81
+ key: :build,
82
+ env_name: 'FL_FLUTTER_BUILD',
83
+ description: 'Type of Flutter build (e.g. apk, appbundle, ios)',
84
+ optional: true,
85
+ type: String,
86
+ ),
87
+ FastlaneCore::ConfigItem.new(
88
+ key: :debug,
89
+ env_name: 'FL_FLUTTER_DEBUG',
90
+ description: 'Build a Debug version of the app if true',
91
+ optional: true,
92
+ type: Boolean,
93
+ default_value: false,
94
+ ),
95
+ FastlaneCore::ConfigItem.new(
96
+ key: :codesign,
97
+ env_name: 'FL_FLUTTER_CODESIGN',
98
+ description: 'Set to false to skip iOS app signing. This may be ' \
99
+ 'useful e.g. on CI or when signed later by Fastlane "sigh"',
100
+ optional: true,
101
+ type: Boolean,
102
+ ),
103
+ FastlaneCore::ConfigItem.new(
104
+ key: :build_number,
105
+ env_name: 'FL_FLUTTER_BUILD_NUMBER',
106
+ description: 'Override build number specified in pubspec.yaml',
107
+ optional: true,
108
+ type: Integer,
109
+ ),
110
+ FastlaneCore::ConfigItem.new(
111
+ key: :build_name,
112
+ env_name: 'FL_FLUTTER_BUILD_NAME',
113
+ description: <<-'DESCRIPTION',
114
+ Override build name specified in pubspec.yaml.
115
+ NOTE: for App Store, build name must be in the format of at most 3
116
+ integeres separated by a dot (".").
117
+ DESCRIPTION
118
+ optional: true,
119
+ ),
120
+ ]
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,68 @@
1
+ require 'fastlane/action'
2
+ require_relative '../base/flutter_action_base'
3
+ require_relative '../helper/flutter_helper'
4
+ require_relative '../helper/flutter_generate_intl_helper'
5
+ require_relative '../helper/flutter_generate_build_runner_helper'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ class FlutterGenerateAction < Action
10
+ extend FlutterActionBase
11
+
12
+ def self.run(params)
13
+ Helper::FlutterHelper.flutter(*%w(packages get), log: false)
14
+
15
+ # In an ideal world, this should be a part of build_runner:
16
+ # https://github.com/dart-lang/intl_translation/issues/32
17
+ # Generate Intl messages before others, since these are static and
18
+ # others may be not.
19
+ if generate_translation?
20
+ Helper::FlutterGenerateIntlHelper.generate(
21
+ params[:intl_strings_file], params[:intl_strings_locale]
22
+ )
23
+ end
24
+
25
+ if Helper::FlutterHelper.dev_dependency?('build_runner')
26
+ UI.message('Found build_runner dependency, running build...')
27
+ Helper::FlutterGenerateBuildRunnerHelper.build
28
+ end
29
+ end
30
+
31
+ def self.generate_translation?
32
+ Helper::FlutterHelper.dev_dependency?('intl_translation')
33
+ end
34
+
35
+ def self.description
36
+ 'According to package:intl, take $strings_file and generate ' \
37
+ '${strings_file.dirname}/arb/intl_messages.arb, then take all files ' \
38
+ 'matching ${strings_file.dirname}/intl_*.arb, fix them and generate ' \
39
+ '.dart files from them'
40
+ end
41
+
42
+ def self.available_options
43
+ # https://docs.fastlane.tools/advanced/actions/#configuration-files
44
+ [
45
+ FastlaneCore::ConfigItem.new(
46
+ key: :intl_strings_file,
47
+ env_name: 'FL_FLUTTER_INTL_STRINGS_FILE',
48
+ description: 'Path to source .dart file with Intl.message calls',
49
+ verify_block: proc do |value|
50
+ if generate_translation?
51
+ unless File.exist?(value)
52
+ UI.user_error!("File `#{value}' does not exist")
53
+ end
54
+ end
55
+ end,
56
+ default_value: 'lib/intl/intl.dart',
57
+ ),
58
+ FastlaneCore::ConfigItem.new(
59
+ key: :intl_strings_locale,
60
+ env_name: 'FL_FLUTTER_INTL_STRINGS_LOCALE',
61
+ description: 'Locale of the default data in the strings_file',
62
+ optional: true,
63
+ ),
64
+ ]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/action'
2
+
3
+ module Fastlane
4
+ module Actions
5
+ module FlutterActionBase
6
+ def authors
7
+ ['github.com/dotdoom']
8
+ end
9
+
10
+ def is_supported?(platform)
11
+ # Also support nil (root lane).
12
+ [nil, :ios, :android].include?(platform)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ require 'fastlane_core/ui/ui'
2
+ require 'fileutils'
3
+
4
+ module Fastlane
5
+ module Helper
6
+ class FlutterBootstrapHelper
7
+ def self.accept_licenses(licenses_directory, licenses)
8
+ FileUtils.mkdir_p(licenses_directory)
9
+ licenses.each_pair do |license, hash|
10
+ license_file = File.join(licenses_directory, license)
11
+ next if File.exist?(license_file) &&
12
+ File.readlines(license_file).map(&:strip).include?(hash)
13
+ UI.message("Updating Android SDK license in #{license_file}...")
14
+ File.open(license_file, 'a') { |f| f.puts('', hash) }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ require 'yaml'
2
+
3
+ module Fastlane
4
+ module Helper
5
+ class FlutterGenerateBuildRunnerHelper
6
+ def self.build
7
+ Helper::FlutterHelper.flutter(
8
+ *%w(packages pub run build_runner build --delete-conflicting-outputs),
9
+ log: false,
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,110 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'set'
4
+ require 'yaml'
5
+
6
+ require_relative 'flutter_helper'
7
+
8
+ module Fastlane
9
+ module Helper
10
+ end
11
+ end
12
+
13
+ class Fastlane::Helper::FlutterGenerateIntlHelper
14
+ def self.generate(messages_filename, messages_locale = nil)
15
+ dart_files_dirname = File.dirname(messages_filename)
16
+ arb_files_dirname = File.join(dart_files_dirname, 'arb')
17
+ full_arb_filename = generate_arb_from_dart(
18
+ messages_filename, messages_locale, arb_files_dirname
19
+ )
20
+
21
+ arb_filenames = amend_arb_files(arb_files_dirname, full_arb_filename)
22
+
23
+ unless messages_locale
24
+ # Don't generate .dart for the ARB generated from original, unless it
25
+ # has its own locale.
26
+ arb_filenames.delete(full_arb_filename)
27
+ end
28
+
29
+ Fastlane::UI.message('Generating .dart files from .arb...')
30
+ Fastlane::Helper::FlutterHelper.flutter(
31
+ *%W(packages pub run intl_translation:generate_from_arb
32
+ --output-dir=#{dart_files_dirname}
33
+ --no-use-deferred-loading
34
+ #{messages_filename}) + arb_filenames
35
+ )
36
+ end
37
+
38
+ def self.amend_arb_files(arb_files_dirname, full_arb_filename)
39
+ full_arb_json = JSON.parse(File.read(full_arb_filename))
40
+
41
+ # Sort files for consistency, because generated messages_all.dart will
42
+ # have imports ordered as in the command line below.
43
+ arb_filenames = Dir.glob(File.join(arb_files_dirname, 'intl_*.arb')).sort
44
+ arb_filenames.each do |arb_filename|
45
+ arb_json = JSON.parse(File.read(arb_filename))
46
+ if arb_filename != full_arb_filename
47
+ Fastlane::UI.message("Amending #{arb_filename}...")
48
+ full_arb_json.each_pair do |k, v|
49
+ # Ignore @@keys. We don't want to copy @@locale over all files, and
50
+ # it's often unspecified to be inferred from file name.
51
+ arb_json[k] ||= v unless k.start_with?('@@')
52
+ end
53
+ arb_json.keep_if { |k| full_arb_json.key?(k) }
54
+ end
55
+ File.write(arb_filename, JSON.pretty_generate(arb_json) + "\n")
56
+ end
57
+ end
58
+
59
+ def self.generate_arb_from_dart(dart_filename, dart_locale, arb_dirname)
60
+ arb_filename = File.join(arb_dirname, 'intl_messages.arb')
61
+ Fastlane::UI.message("Generating #{arb_filename} from #{dart_filename}...")
62
+
63
+ if File.exist?(arb_filename)
64
+ arb_file_was = File.read(arb_filename)
65
+ else
66
+ # The file may not exist on the first run. Then it's also probable that
67
+ # the output directory does not exist yet.
68
+ FileUtils.mkdir_p(arb_dirname)
69
+ end
70
+
71
+ extract_to_arb_options = ["--output-dir=#{arb_dirname}"]
72
+ if dart_locale
73
+ extract_to_arb_options.push("--locale=#{dart_locale}")
74
+ end
75
+
76
+ Fastlane::Helper::FlutterHelper.flutter(
77
+ *%w(packages pub run intl_translation:extract_to_arb),
78
+ *extract_to_arb_options, dart_filename
79
+ )
80
+
81
+ # intl will update @@last_modified even if there are no updates; this
82
+ # leaves Git directory unnecessary dirty. If that's the only change,
83
+ # just restore the previous contents.
84
+ if arb_file_was
85
+ if restore_last_modified(arb_filename, arb_file_was)
86
+ Fastlane::UI.message(
87
+ "@@last_modified has been restored in #{arb_filename}"
88
+ )
89
+ end
90
+ end
91
+
92
+ arb_filename
93
+ end
94
+
95
+ def self.restore_last_modified(filename, old_content)
96
+ new_content_tree = JSON.parse(File.read(filename))
97
+ old_content_tree = JSON.parse(old_content)
98
+ new_content_tree['@@last_modified'] = old_content_tree['@@last_modified']
99
+
100
+ # Use to_json to compare the objects deep and in consistent format.
101
+ if new_content_tree.to_json == old_content_tree.to_json
102
+ # Except for the @@last_modified attribute that we replaced
103
+ # above, the objects are identical. Restore previous timestamp.
104
+ File.write(filename, old_content)
105
+ return true
106
+ end
107
+
108
+ false
109
+ end
110
+ end
@@ -1,147 +1,35 @@
1
- require 'fastlane_core/ui/ui'
2
- require 'fileutils'
3
- require 'json'
4
- require 'set'
5
- require 'tempfile'
1
+ require 'yaml'
6
2
 
7
3
  module Fastlane
8
- # UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
9
-
10
4
  module Helper
11
5
  class FlutterHelper
12
- def self.restore_l10n_timestamp(file_name, old_content)
13
- new_content_tree = JSON.parse(File.read(file_name))
14
- old_content_tree = JSON.parse(old_content)
15
-
16
- new_content_tree['@@last_modified'] =
17
- old_content_tree['@@last_modified']
18
-
19
- # Use to_json to compare the objects deep and in consistent format.
20
- if new_content_tree.to_json == old_content_tree.to_json
21
- # Except for the @@last_modified attribute that we replaced
22
- # above, the objects are identical. Restore previous timestamp.
23
- File.write(file_name, old_content)
24
- return true
25
- end
26
-
27
- false
28
- end
29
-
30
- def self.reformat_arb(file_name)
31
- pretty_content = JSON.pretty_generate(JSON.parse(File.read(file_name)))
32
-
33
- File.write(file_name, pretty_content + "\n")
34
- end
35
-
36
- def self.compare_arb(origin, sample)
37
- is_significant_key = ->(key) { !key.start_with?('@') }
38
-
39
- origin_keys = Set.new(JSON.parse(File.read(origin))
40
- .keys
41
- .select(&is_significant_key))
42
- sample_keys = Set.new(JSON.parse(File.read(sample))
43
- .keys
44
- .select(&is_significant_key))
45
-
46
- keys_not_in_sample = origin_keys - sample_keys
47
- keys_not_in_origin = sample_keys - origin_keys
48
-
49
- differencies = []
50
- if keys_not_in_sample.any?
51
- differencies.push("Translation string(s): " \
52
- "#{keys_not_in_sample.to_a.join(', ')}; " \
53
- "are missing")
54
- end
55
- if keys_not_in_origin.any?
56
- differencies.push("Translation string(s): " \
57
- "#{keys_not_in_origin.to_a.join(', ')}; " \
58
- "are unused")
59
- end
60
- differencies
6
+ def self.flutter(*argv, &block)
7
+ # TODO(dotdoom): explain special keys in params, like "log" etc.
8
+ # TODO(dotdoom): most commands set "log: false", which means that the
9
+ # output is lost (even in case of error). Perhaps we
10
+ # could print the output here, via error_callback?
11
+ # https://github.com/fastlane/fastlane/blob/b1495d134eec6681c8d7a544aa3520f1da00c80e/fastlane/lib/fastlane/helper/sh_helper.rb#L73
12
+ Actions.sh(File.join(flutter_sdk_root, 'bin', 'flutter'), *argv, &block)
61
13
  end
62
14
 
63
- def self.build_number(schema)
64
- schema and Integer(schema)
65
- rescue ArgumentError
66
- build_number_source, build_number_base = schema.split('+', 2)
67
-
68
- case build_number_source
69
- when 'vcs'
70
- build_number = Integer(
71
- Actions.sh(*%w(git rev-list --count HEAD)).strip
72
- )
73
- when 'ci'
74
- begin
75
- build_number = Integer(ENV['TRAVIS_BUILD_NUMBER'] ||
76
- ENV['CIRCLE_BUILD_NUM'])
77
- rescue ArgumentError, TypeError
78
- raise if ENV.key?('CI')
79
- raise ArgumentError, 'CI version requested, but not running on a CI'
80
- end
81
- end
82
-
83
- if build_number_base
84
- build_number + Integer(build_number_base)
85
- else
86
- build_number
87
- end
15
+ def self.git(*argv, &block)
16
+ Actions.sh('git', *argv, &block)
88
17
  end
89
18
 
90
- def self.build_name(schema)
91
- if schema && schema =~ /^(\^)?vcs(.*)$/
92
- schema_caret = $1
93
- schema_dirty_mark = $2
94
- vcs_version = Actions.sh(
95
- *%W(git describe --tags --dirty=#{schema_dirty_mark})
96
- ).strip
97
-
98
- # We try to match, otherwise assume vcs_version = $TAG, which means
99
- # that there are 0 commits since the latest tag.
100
- if schema_caret && vcs_version =~ /^
101
- (\d+[.]\d+)-
102
- (\d+)-
103
- g.*?
104
- (#{Regexp.quote(schema_dirty_mark)})?
105
- $/x
106
-
107
- vcs_version = "#{$1}.#{$2}"
108
- # Making the best guess whether it's dirty.
109
- if $3
110
- vcs_version += schema_dirty_mark
111
- end
19
+ def self.flutter_sdk_root
20
+ @flutter_sdk_root ||= File.expand_path(
21
+ if ENV.include?('FLUTTER_SDK_ROOT')
22
+ ENV['FLUTTER_SDK_ROOT']
23
+ elsif flutter_binary = FastlaneCore::CommandExecutor.which('flutter')
24
+ File.dirname(File.dirname(flutter_binary))
25
+ else
26
+ 'vendor/flutter'
112
27
  end
113
-
114
- vcs_version
115
- else
116
- schema
117
- end
28
+ )
118
29
  end
119
30
 
120
- # Bootstrap Flutter application for build with Android SDK:
121
- # https://github.com/flutter/flutter/issues/28076
122
- def self.bootstrap_android(licenses = {})
123
- # Gradle will refuse to install Android SDK unless the SDK directory
124
- # exists and licenses are accepted.
125
- licenses_directory = File.join(android_sdk_root!, 'licenses')
126
- FileUtils.mkdir_p(licenses_directory)
127
- if licenses.any?
128
- licenses.each_pair do |license, hash|
129
- license_file = File.join(licenses_directory, license)
130
- unless File.exist?(license_file) &&
131
- File.readlines(license_file).map(&:strip).include?(hash)
132
- File.open(license_file, 'a') { |f| f.puts('', hash) }
133
- end
134
- end
135
- end
136
- end
137
-
138
- def self.android_sdk_root!
139
- (ENV['ANDROID_HOME'] || ENV['ANDROID_SDK_ROOT']).tap do |path|
140
- unless path
141
- raise 'Android SDK directory environment variables are not set. ' \
142
- 'See https://developer.android.com/studio/command-line/variables'
143
- end
144
- end
31
+ def self.dev_dependency?(package)
32
+ (YAML.load_file('pubspec.yaml')['dev_dependencies'] || {}).key?(package)
145
33
  end
146
34
  end
147
35
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Flutter
3
- VERSION = "0.2.7"
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-flutter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artem Sheremet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-24 00:00:00.000000000 Z
11
+ date: 2019-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -146,6 +146,13 @@ files:
146
146
  - README.md
147
147
  - lib/fastlane/plugin/flutter.rb
148
148
  - lib/fastlane/plugin/flutter/actions/flutter_action.rb
149
+ - lib/fastlane/plugin/flutter/actions/flutter_bootstrap_action.rb
150
+ - lib/fastlane/plugin/flutter/actions/flutter_build_action.rb
151
+ - lib/fastlane/plugin/flutter/actions/flutter_generate_action.rb
152
+ - lib/fastlane/plugin/flutter/base/flutter_action_base.rb
153
+ - lib/fastlane/plugin/flutter/helper/flutter_bootstrap_helper.rb
154
+ - lib/fastlane/plugin/flutter/helper/flutter_generate_build_runner_helper.rb
155
+ - lib/fastlane/plugin/flutter/helper/flutter_generate_intl_helper.rb
149
156
  - lib/fastlane/plugin/flutter/helper/flutter_helper.rb
150
157
  - lib/fastlane/plugin/flutter/version.rb
151
158
  homepage: https://github.com/dotdoom/fastlane-plugin-flutter