fastlane-plugin-flutter 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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