fastlane 2.62.0.beta.20171016010004 → 2.62.0.beta.20171017010003

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: e48c62acc810d151573862aff11a7c34322cd3b2
4
- data.tar.gz: 5545f680d045794bb9b749febff528085f748533
3
+ metadata.gz: f14604abb941543613b3505e11bf099dccccf4ab
4
+ data.tar.gz: f62ef3b052d856ec84948d52521321455fedb5be
5
5
  SHA512:
6
- metadata.gz: 6199c80457f0b54f09cc8a86527525ae0f5ffb1ecd375521e04cc2951e21ae116d1dfb1778aaedec59f95c3ec3c4e696371491f77757ce7bcbb6015cfd2ee724
7
- data.tar.gz: 5b2b29177b098219e07f06d10c05605ac3d5237ae471b25cf2d353cca1c381f7a1db1240ce958750c42570b9569792b4260838ef64ce723883f050918b6c8914
6
+ metadata.gz: 03f1513c1a01cc9a51aeb3642907bc93c868f8e1764cee102046f1b4dee88489e6a86ea0e076d8203794d916bc612a31b2198ddd5ffca9a0d88710df27742481
7
+ data.tar.gz: 0318818369814716e8b1f4403276ce4b4d7673e49a2b6ae2aaddda43638ddf89a35d5a61cab5b1656e6e118ebbe1d9e3a8c320d2e830eee39eff0141f4118a00
@@ -150,10 +150,6 @@ module Fastlane
150
150
  # @!group Other things
151
151
  #####################################################
152
152
 
153
- def collector
154
- runner.collector
155
- end
156
-
157
153
  # Is the given key a platform block or a lane?
158
154
  def is_platform_block?(key)
159
155
  UI.crash!('No key given') unless key
@@ -217,8 +213,13 @@ module Fastlane
217
213
  actions_path = File.join(File.expand_path("..", path), 'actions')
218
214
  Fastlane::Actions.load_external_actions(actions_path) if File.directory?(actions_path)
219
215
 
220
- collector.did_launch_action(:import)
221
- parse(File.read(path), path)
216
+ action_launched('import')
217
+
218
+ return_value = parse(File.read(path), path)
219
+
220
+ action_completed('import', status: FastlaneCore::ActionCompletionStatus::SUCCESS)
221
+
222
+ return return_value
222
223
  end
223
224
 
224
225
  # @param url [String] The git URL to clone the repository from
@@ -230,7 +231,7 @@ module Fastlane
230
231
  Actions.execute_action('import_from_git') do
231
232
  require 'tmpdir'
232
233
 
233
- collector.did_launch_action(:import_from_git)
234
+ action_launched('import_from_git')
234
235
 
235
236
  # Checkout the repo
236
237
  repo_name = url.split("/").last
@@ -258,7 +259,11 @@ module Fastlane
258
259
  # We don't care about a failure here, as local actions are optional
259
260
  end
260
261
 
261
- import(File.join(clone_folder, path))
262
+ return_value = import(File.join(clone_folder, path))
263
+
264
+ action_completed('import_from_git', status: FastlaneCore::ActionCompletionStatus::SUCCESS)
265
+
266
+ return return_value
262
267
  end
263
268
  end
264
269
  end
@@ -272,21 +277,36 @@ module Fastlane
272
277
  # Overwrite this, since there is already a 'say' method defined in the Ruby standard library
273
278
  value ||= yield
274
279
  Actions.execute_action('say') do
275
- collector.did_launch_action(:say)
276
- Fastlane::Actions::SayAction.run([value])
280
+ action_launched('say')
281
+ return_value = Fastlane::Actions::SayAction.run([value])
282
+ action_completed('say', status: FastlaneCore::ActionCompletionStatus::SUCCESS)
283
+ return return_value
277
284
  end
278
285
  end
279
286
 
280
287
  def puts(value)
281
288
  # Overwrite this, since there is already a 'puts' method defined in the Ruby standard library
282
289
  value ||= yield if block_given?
283
- collector.did_launch_action(:puts)
284
- Fastlane::Actions::PutsAction.run([value])
290
+
291
+ action_launched('puts')
292
+ return_value = Fastlane::Actions::PutsAction.run([value])
293
+ action_completed('puts', status: FastlaneCore::ActionCompletionStatus::SUCCESS)
294
+ return return_value
285
295
  end
286
296
 
287
297
  def test(params = {})
288
298
  # Overwrite this, since there is already a 'test' method defined in the Ruby standard library
289
299
  self.runner.try_switch_to_lane(:test, [params])
290
300
  end
301
+
302
+ def action_launched(action_name)
303
+ action_launch_context = FastlaneCore::ActionLaunchContext.context_for_action_name(action_name, args: ARGV)
304
+ FastlaneCore.session.action_launched(launch_context: action_launch_context)
305
+ end
306
+
307
+ def action_completed(action_name, status: nil)
308
+ completion_context = FastlaneCore::ActionCompletionContext.context_for_action_name(action_name, args: ARGV, status: status)
309
+ FastlaneCore.session.action_completed(completion_context: completion_context)
310
+ end
291
311
  end
292
312
  end
@@ -38,6 +38,8 @@ module Fastlane
38
38
 
39
39
  platform, lane = choose_lane(ff, platform) unless lane
40
40
 
41
+ FastlaneCore.session.is_fastfile = true
42
+
41
43
  # xcodeproj has a bug in certain versions that causes it to change directories
42
44
  # and not return to the original working directory
43
45
  # https://github.com/CocoaPods/Xcodeproj/issues/426
@@ -76,8 +78,6 @@ module Fastlane
76
78
 
77
79
  # All the finishing up that needs to be done
78
80
  def self.finish_fastlane(ff, duration, error)
79
- ff.runner.did_finish
80
-
81
81
  # Finished with all the lanes
82
82
  Fastlane::JUnitGenerator.generate(Fastlane::Actions.executed_actions)
83
83
  print_table(Fastlane::Actions.executed_actions)
@@ -197,7 +197,10 @@ module Fastlane
197
197
 
198
198
  # Actually switch lane now
199
199
  self.current_lane = new_lane
200
- collector.did_launch_action(:lane_switch)
200
+
201
+ launch_context = FastlaneCore::ActionLaunchContext.context_for_action_name('lane_switch', args: ARGV)
202
+ FastlaneCore.session.action_launched(launch_context: launch_context)
203
+
201
204
  result = block.call(parameters.first || {}) # to always pass a hash
202
205
  self.current_lane = original_lane
203
206
 
@@ -218,11 +221,12 @@ module Fastlane
218
221
  custom_dir ||= ".."
219
222
  end
220
223
 
221
- collector.did_launch_action(method_sym)
222
-
223
224
  verify_supported_os(method_sym, class_ref)
224
225
 
225
226
  begin
227
+ launch_context = FastlaneCore::ActionLaunchContext.context_for_action_name(method_sym.to_s, args: ARGV)
228
+ FastlaneCore.session.action_launched(launch_context: launch_context)
229
+
226
230
  Dir.chdir(custom_dir) do # go up from the fastlane folder, to the project folder
227
231
  # If another action is calling this action, we shouldn't show it in the summary
228
232
  # (see https://github.com/fastlane/fastlane/issues/4546)
@@ -249,7 +253,11 @@ module Fastlane
249
253
  end
250
254
 
251
255
  class_ref.runner = self # needed to call another action form an action
252
- class_ref.run(arguments)
256
+ return_value = class_ref.run(arguments)
257
+
258
+ action_completed(method_sym.to_s, status: FastlaneCore::ActionCompletionStatus::SUCCESS)
259
+
260
+ return return_value
253
261
  end
254
262
  end
255
263
  rescue Interrupt => e
@@ -258,17 +266,25 @@ module Fastlane
258
266
  raise e
259
267
  rescue FastlaneCore::Interface::FastlaneError => e # user_error!
260
268
  FastlaneCore::CrashReporter.report_crash(exception: e)
261
- collector.did_raise_error(method_sym) if e.fastlane_should_report_metrics?
269
+ action_completed(method_sym.to_s, status: FastlaneCore::ActionCompletionStatus::USER_ERROR, exception: e)
262
270
  raise e
263
271
  rescue Exception => e # rubocop:disable Lint/RescueException
264
272
  # high chance this is actually FastlaneCore::Interface::FastlaneCrash, but can be anything else
265
273
  # Catches all exceptions, since some plugins might use system exits to get out
266
274
  FastlaneCore::CrashReporter.report_crash(exception: e)
267
- collector.did_crash(method_sym) if e.fastlane_should_report_metrics?
275
+
276
+ action_completed(method_sym.to_s, status: FastlaneCore::ActionCompletionStatus::FAILED, exception: e)
268
277
  raise e
269
278
  end
270
279
  end
271
280
 
281
+ def action_completed(action_name, status: nil, exception: nil)
282
+ if exception.nil? || exception.fastlane_should_report_metrics?
283
+ action_completion_context = FastlaneCore::ActionCompletionContext.context_for_action_name(action_name, args: ARGV, status: status)
284
+ FastlaneCore.session.action_completed(completion_context: action_completion_context)
285
+ end
286
+ end
287
+
272
288
  def execute_flow_block(block, current_platform, lane, parameters)
273
289
  # Call the platform specific block and default back to the general one
274
290
  block[current_platform].call(lane, parameters) if block[current_platform] && current_platform
@@ -287,15 +303,6 @@ module Fastlane
287
303
  end
288
304
  end
289
305
 
290
- def collector
291
- @collector ||= ActionCollector.new
292
- end
293
-
294
- # Fastfile was finished executing
295
- def did_finish
296
- collector.did_finish
297
- end
298
-
299
306
  # Called internally to setup the runner object
300
307
  #
301
308
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.62.0.beta.20171016010004'.freeze
2
+ VERSION = '2.62.0.beta.20171017010003'.freeze
3
3
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
4
4
  MINIMUM_XCODE_RELEASE = "7.0".freeze
5
5
  end
@@ -40,6 +40,11 @@ require 'fastlane_core/ui/errors/fastlane_crash'
40
40
  require 'fastlane_core/ui/errors/fastlane_shell_error'
41
41
  require 'fastlane_core/ui/errors/fastlane_common_error'
42
42
  require 'fastlane_core/test_parser'
43
+ require 'fastlane_core/analytics/action_completion_context'
44
+ require 'fastlane_core/analytics/action_launch_context'
45
+ require 'fastlane_core/analytics/analytics_event_builder'
46
+ require 'fastlane_core/analytics/analytics_ingester_client'
47
+ require 'fastlane_core/analytics/analytics_session'
43
48
 
44
49
  # Third Party code
45
50
  require 'colored'
@@ -51,6 +56,19 @@ require 'fastlane_core/ui/fastlane_runner' # monkey patch
51
56
  module FastlaneCore
52
57
  ROOT = Pathname.new(File.expand_path('../..', __FILE__))
53
58
 
59
+ # Session is used to report usage metrics.
60
+ # If you opt out, we will not send anything.
61
+ # You can confirm this by observing how we use the environment variable: FASTLANE_OPT_OUT_USAGE
62
+ # Specifically, in AnalyticsSession.finalize_session
63
+ # Learn more at https://github.com/fastlane/fastlane#metrics
64
+ def self.session
65
+ @session ||= AnalyticsSession.new
66
+ end
67
+
68
+ def self.reset_session
69
+ @session = nil
70
+ end
71
+
54
72
  # A directory that's being used to user-wide fastlane configs
55
73
  # This directory is also used for the bundled fastlane
56
74
  # Since we don't want to access FastlaneCore from spaceship
@@ -0,0 +1,29 @@
1
+ module FastlaneCore
2
+ class ActionCompletionStatus
3
+ SUCCESS = 'success'
4
+ FAILED = 'failed' # fastlane crashes unrelated to user_error!
5
+ USER_ERROR = 'user_error' # Anytime a user_error! is triggered
6
+ INTERRUPTED = 'interrupted'
7
+ end
8
+
9
+ class ActionCompletionContext
10
+ attr_accessor :p_hash
11
+ attr_accessor :action_name
12
+ attr_accessor :status
13
+
14
+ def initialize(p_hash: nil, action_name: nil, status: nil)
15
+ @p_hash = p_hash
16
+ @action_name = action_name
17
+ @status = status
18
+ end
19
+
20
+ def self.context_for_action_name(action_name, args: nil, status: nil)
21
+ app_id_guesser = FastlaneCore::AppIdentifierGuesser.new(args: args)
22
+ return self.new(
23
+ action_name: action_name,
24
+ p_hash: app_id_guesser.p_hash,
25
+ status: status
26
+ )
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ require 'fastlane_core/helper'
2
+
3
+ module FastlaneCore
4
+ class ActionLaunchContext
5
+ UNKNOWN_P_HASH = 'unknown'
6
+
7
+ attr_accessor :action_name
8
+ attr_accessor :p_hash
9
+ attr_accessor :platform
10
+
11
+ def initialize(action_name: nil, p_hash: UNKNOWN_P_HASH, platform: nil)
12
+ @action_name = action_name
13
+ @p_hash = p_hash
14
+ @platform = platform
15
+ end
16
+
17
+ def self.context_for_action_name(action_name, args: nil)
18
+ app_id_guesser = FastlaneCore::AppIdentifierGuesser.new(args: args)
19
+ return self.new(
20
+ action_name: action_name,
21
+ p_hash: app_id_guesser.p_hash,
22
+ platform: app_id_guesser.platform
23
+ )
24
+ end
25
+
26
+ def build_tool_version
27
+ if platform == :android
28
+ return 'android'
29
+ else
30
+ return "Xcode #{Helper.xcode_version}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,50 @@
1
+ module FastlaneCore
2
+ class AnalyticsEventBuilder
3
+ attr_accessor :base_hash
4
+ attr_accessor :action_name
5
+
6
+ def initialize(oauth_app_name: nil, p_hash: nil, session_id: nil, action_name: nil, timestamp_millis: (Time.now.to_f * 1000).to_i)
7
+ @action_name = action_name
8
+ @base_hash = {
9
+ event_source: {
10
+ oauth_app_name: oauth_app_name,
11
+ product: 'fastlane'
12
+ },
13
+ actor: {
14
+ name: p_hash,
15
+ detail: session_id
16
+ },
17
+ millis_since_epoch: timestamp_millis,
18
+ version: 1
19
+ }
20
+ end
21
+
22
+ def launched_event(primary_target_hash: nil, secondary_target_hash: nil)
23
+ return new_event(
24
+ stage: 'launched',
25
+ primary_target_hash: primary_target_hash,
26
+ secondary_target_hash: secondary_target_hash
27
+ )
28
+ end
29
+
30
+ def completed_event(primary_target_hash: nil, secondary_target_hash: nil)
31
+ return new_event(
32
+ stage: 'completed',
33
+ primary_target_hash: primary_target_hash,
34
+ secondary_target_hash: secondary_target_hash
35
+ )
36
+ end
37
+
38
+ def new_event(stage: nil, primary_target_hash: nil, secondary_target_hash: nil)
39
+ raise 'Need at least a primary_target_hash' if primary_target_hash.nil?
40
+ event = base_hash.dup
41
+ event[:action] = {
42
+ name: stage,
43
+ detail: action_name
44
+ }
45
+ event[:primary_target] = primary_target_hash
46
+ event[:secondary_target] = secondary_target_hash unless secondary_target_hash.nil?
47
+ return event
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ module FastlaneCore
2
+ class AnalyticsIngesterClient
3
+ def post_events(events)
4
+ unless Helper.test?
5
+ fork do
6
+ send_request(json: { analytics: events }.to_json)
7
+ end
8
+ end
9
+ return true
10
+ end
11
+
12
+ def send_request(json: nil, retries: 2)
13
+ post_request(body: json)
14
+ rescue
15
+ retries -= 1
16
+ retry if retries >= 0
17
+ end
18
+
19
+ def post_request(body: nil)
20
+ if ENV['METRICS_DEBUG']
21
+ write_json(body)
22
+ end
23
+ url = ENV["FASTLANE_METRICS_URL"] || "https://fastlane-metrics.fabric.io"
24
+
25
+ require 'faraday'
26
+ connection = Faraday.new(url) do |conn|
27
+ conn.adapter Faraday.default_adapter
28
+ if ENV['METRICS_DEBUG']
29
+ conn.proxy = "https://127.0.0.1:8888"
30
+ conn.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
31
+ end
32
+ end
33
+ connection.post do |req|
34
+ req.url '/public'
35
+ req.headers['Content-Type'] = 'application/json'
36
+ req.body = body
37
+ end
38
+ end
39
+
40
+ # This method is only for debugging purposes
41
+ def write_json(body)
42
+ File.write("#{ENV['HOME']}/Desktop/mock_analytics-#{Time.now.to_i}.json", body)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,201 @@
1
+ require 'fastlane_core/analytics/analytics_ingester_client'
2
+
3
+ module FastlaneCore
4
+ class AnalyticsSession
5
+ attr_accessor :session_id
6
+ attr_accessor :client
7
+ attr_accessor :events
8
+ attr_accessor :fastfile_id
9
+ attr_accessor :is_fastfile
10
+ alias fastfile? is_fastfile
11
+
12
+ # make this a method so that we can override it in monkey patches
13
+ def oauth_app_name
14
+ return 'fastlane_v2'
15
+ end
16
+
17
+ def initialize(analytics_ingester_client: AnalyticsIngesterClient.new)
18
+ require 'securerandom'
19
+ @session_id = SecureRandom.uuid
20
+ @client = analytics_ingester_client
21
+ @events = []
22
+ @is_fastfile = false
23
+ end
24
+
25
+ def backfill_p_hashes(p_hash: nil)
26
+ return if p_hash.nil? || p_hash == ActionLaunchContext::UNKNOWN_P_HASH || @events.count == 0
27
+ @events.reverse_each do |event|
28
+ # event[:actor][:name] is the field in which we store the p_hash
29
+ # to be sent to analytics ingester.
30
+ # If they are nil, we want to fill them in until we reach
31
+ # an event that already has a p_hash.
32
+ if event[:actor][:name].nil? || event[:actor][:name] == ActionLaunchContext::UNKNOWN_P_HASH
33
+ event[:actor][:name] = p_hash
34
+ else
35
+ break
36
+ end
37
+ end
38
+ end
39
+
40
+ def action_launched(launch_context: nil)
41
+ backfill_p_hashes(p_hash: launch_context.p_hash)
42
+
43
+ builder = AnalyticsEventBuilder.new(
44
+ oauth_app_name: oauth_app_name,
45
+ p_hash: launch_context.p_hash,
46
+ session_id: session_id,
47
+ action_name: launch_context.action_name
48
+ )
49
+
50
+ @events << builder.launched_event(
51
+ primary_target_hash: {
52
+ name: 'fastlane_version',
53
+ detail: fastlane_version
54
+ }
55
+ )
56
+
57
+ @events << builder.launched_event(
58
+ primary_target_hash: {
59
+ name: 'install_method',
60
+ detail: install_method
61
+ }
62
+ )
63
+
64
+ @events << builder.launched_event(
65
+ primary_target_hash: {
66
+ name: 'operating_system',
67
+ detail: operating_system
68
+ },
69
+ secondary_target_hash: {
70
+ name: 'version',
71
+ detail: operating_system_version
72
+ }
73
+ )
74
+
75
+ @events << builder.launched_event(
76
+ primary_target_hash: {
77
+ name: 'build_tool_version',
78
+ detail: launch_context.build_tool_version
79
+ }
80
+ )
81
+
82
+ @events << builder.launched_event(
83
+ primary_target_hash: {
84
+ name: 'ci',
85
+ detail: ci?.to_s
86
+ }
87
+ )
88
+
89
+ @events << builder.launched_event(
90
+ primary_target_hash: {
91
+ name: 'fastfile',
92
+ detail: fastfile?.to_s
93
+ },
94
+ secondary_target_hash: {
95
+ name: 'fastfile_id',
96
+ detail: fastfile_id.to_s
97
+ }
98
+ )
99
+
100
+ @events << builder.launched_event(
101
+ primary_target_hash: {
102
+ name: 'platform',
103
+ detail: launch_context.platform.to_s
104
+ }
105
+ )
106
+
107
+ @events << builder.launched_event(
108
+ primary_target_hash: {
109
+ name: 'ruby_version',
110
+ detail: ruby_version
111
+ }
112
+ )
113
+ end
114
+
115
+ def is_fastfile=(value)
116
+ if value
117
+ # If true, update all of the events to reflect
118
+ # that the execution is running within a Fastfile context.
119
+ # We don't want to update if this is false because once we
120
+ # detect a true value, that is the one to be trusted
121
+ @events.reverse_each do |event|
122
+ event[:primary_target][:name] == 'fastfile' ? event[:primary_target][:detail] = value.to_s : next
123
+ end
124
+ end
125
+ @is_fastfile = value
126
+ end
127
+
128
+ def action_completed(completion_context: nil)
129
+ backfill_p_hashes(p_hash: completion_context.p_hash)
130
+
131
+ builder = AnalyticsEventBuilder.new(
132
+ oauth_app_name: oauth_app_name,
133
+ p_hash: completion_context.p_hash,
134
+ session_id: session_id,
135
+ action_name: completion_context.action_name
136
+ )
137
+
138
+ @events << builder.completed_event(
139
+ primary_target_hash: {
140
+ name: 'status',
141
+ detail: completion_context.status
142
+ }
143
+ )
144
+ end
145
+
146
+ def finalize_session
147
+ # If our users want to opt out of usage metrics, don't post the events.
148
+ # Learn more at https://github.com/fastlane/fastlane#metrics
149
+ return if FastlaneCore::Env.truthy?("FASTLANE_OPT_OUT_USAGE")
150
+
151
+ client.post_events(@events)
152
+ end
153
+
154
+ def fastlane_version
155
+ return Fastlane::VERSION
156
+ end
157
+
158
+ def ruby_version
159
+ patch_level = RUBY_PATCHLEVEL == 0 ? nil : "p#{RUBY_PATCHLEVEL}"
160
+ return "#{RUBY_VERSION}#{patch_level}"
161
+ end
162
+
163
+ def operating_system
164
+ return "macOS" if RUBY_PLATFORM.downcase.include?("darwin")
165
+ return "Windows" if RUBY_PLATFORM.downcase.include?("mswin")
166
+ return "Linux" if RUBY_PLATFORM.downcase.include?("linux")
167
+ return "Unknown"
168
+ end
169
+
170
+ def install_method
171
+ if Helper.rubygems?
172
+ return 'gem'
173
+ elsif Helper.bundler?
174
+ return 'bundler'
175
+ elsif Helper.mac_app?
176
+ return 'mac_app'
177
+ elsif Helper.contained_fastlane?
178
+ return 'standalone'
179
+ elsif Helper.homebrew?
180
+ return 'homebrew'
181
+ else
182
+ return 'unknown'
183
+ end
184
+ end
185
+
186
+ def ci?
187
+ return Helper.is_ci?
188
+ end
189
+
190
+ def operating_system_version
191
+ os = self.operating_system
192
+ case os
193
+ when "macOS"
194
+ return `SW_VERS -productVersion`.strip
195
+ else
196
+ # Need to test in Windows and Linux... not sure this is enough
197
+ return Gem::Platform.local.version
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,64 @@
1
+ require 'fastlane_core/android_package_name_guesser'
2
+ require 'fastlane_core/ios_app_identifier_guesser'
3
+
4
+ module FastlaneCore
5
+ class AppIdentifierGuesser
6
+ attr_accessor :args
7
+ attr_accessor :gem_name
8
+ attr_accessor :platform
9
+ attr_accessor :p_hash
10
+ attr_accessor :app_id
11
+
12
+ def initialize(args: nil, gem_name: 'fastlane')
13
+ @args = args
14
+ @gem_name = gem_name
15
+
16
+ @app_id = android_app_identifier(args, gem_name)
17
+ @platform = nil # since have a state in-between runs
18
+ if @app_id
19
+ @platform = :android
20
+ else
21
+ @app_id = ios_app_identifier(args)
22
+ @platform = :ios if @app_id
23
+ end
24
+
25
+ @p_hash = generate_p_hash(@app_id)
26
+ end
27
+
28
+ # To not count the same projects multiple time for the number of launches
29
+ # Learn more at https://github.com/fastlane/fastlane#metrics
30
+ # Use the `FASTLANE_OPT_OUT_USAGE` variable to opt out
31
+ # The resulting value is e.g. ce12f8371df11ef6097a83bdf2303e4357d6f5040acc4f76019489fa5deeae0d
32
+ def generate_p_hash(app_id)
33
+ unless !FastlaneCore::Env.truthy?("FASTLANE_OPT_OUT_USAGE") && !app_id.nil?
34
+ return nil
35
+ end
36
+
37
+ require 'credentials_manager'
38
+ return Digest::SHA256.hexdigest("p#{app_id}fastlan3_SAlt") # hashed + salted the bundle identifier
39
+ rescue
40
+ return nil # we don't want this method to cause a crash
41
+ end
42
+
43
+ # (optional) Returns the app identifier for the current tool
44
+ def ios_app_identifier(args)
45
+ return FastlaneCore::IOSAppIdentifierGuesser.guess_app_identifier(args)
46
+ rescue
47
+ nil # we don't want this method to cause a crash
48
+ end
49
+
50
+ # (optional) Returns the app identifier for the current tool
51
+ # supply and screengrab use different param names and env variable patterns so we have to special case here
52
+ # example:
53
+ # fastlane supply --skip_upload_screenshots -a beta -p com.test.app should return com.test.app
54
+ # screengrab -a com.test.app should return com.test.app
55
+ def android_app_identifier(args, gem_name)
56
+ app_identifier = FastlaneCore::AndroidPackageNameGuesser.guess_package_name(gem_name, args)
57
+
58
+ # Add Android prefix to prevent collisions if there is an iOS app with the same identifier
59
+ app_identifier ? "android_project_#{app_identifier}" : nil
60
+ rescue
61
+ nil # we don't want this method to cause a crash
62
+ end
63
+ end
64
+ end
@@ -60,8 +60,13 @@ module Commander
60
60
  FastlaneCore::UI.user_error!("fastlane requires a minimum version of Xcode #{Fastlane::MINIMUM_XCODE_RELEASE}, please upgrade and make sure to use `sudo xcode-select -s /Applications/Xcode.app`")
61
61
  end
62
62
 
63
- collector.did_launch_action(@program[:name])
64
- run_active_command
63
+ action_launch_context = FastlaneCore::ActionLaunchContext.context_for_action_name(@program[:name], args: ARGV)
64
+ FastlaneCore.session.action_launched(launch_context: action_launch_context)
65
+
66
+ return_value = run_active_command
67
+
68
+ action_completed(@program[:name], status: FastlaneCore::ActionCompletionStatus::SUCCESS)
69
+ return return_value
65
70
  rescue InvalidCommandError => e
66
71
  # calling `abort` makes it likely that tests stop without failing, so
67
72
  # we'll disable that during tests.
@@ -76,6 +81,7 @@ module Commander
76
81
  if FastlaneCore::Globals.verbose?
77
82
  raise e
78
83
  else
84
+ action_completed(@program[:name], status: FastlaneCore::ActionCompletionStatus::INTERRUPTED, exception: e)
79
85
  puts "\nCancelled... use --verbose to show the stack trace"
80
86
  end
81
87
  rescue \
@@ -116,12 +122,15 @@ module Commander
116
122
  rescue => e # high chance this is actually FastlaneCore::Interface::FastlaneCrash, but can be anything else
117
123
  rescue_unknown_error(e)
118
124
  ensure
119
- collector.did_finish
125
+ FastlaneCore.session.finalize_session
120
126
  end
121
127
  end
122
128
 
123
- def collector
124
- @collector ||= FastlaneCore::ToolCollector.new
129
+ def action_completed(action_name, status: nil, exception: nil)
130
+ if exception.nil? || exception.fastlane_should_report_metrics?
131
+ action_completion_context = FastlaneCore::ActionCompletionContext.context_for_action_name(action_name, args: ARGV, status: status)
132
+ FastlaneCore.session.action_completed(completion_context: action_completion_context)
133
+ end
125
134
  end
126
135
 
127
136
  def rescue_file_error(e)
@@ -145,12 +154,15 @@ module Commander
145
154
 
146
155
  def rescue_unknown_error(e)
147
156
  FastlaneCore::CrashReporter.report_crash(exception: e)
148
- collector.did_crash(@program[:name]) if e.fastlane_should_report_metrics?
157
+
158
+ action_completed(@program[:name], status: FastlaneCore::ActionCompletionStatus::FAILED, exception: e)
159
+
149
160
  handle_unknown_error!(e)
150
161
  end
151
162
 
152
163
  def rescue_fastlane_error(e)
153
- collector.did_raise_error(@program[:name]) if e.fastlane_should_report_metrics?
164
+ action_completed(@program[:name], status: FastlaneCore::ActionCompletionStatus::USER_ERROR, exception: e)
165
+
154
166
  show_github_issues(e.message) if e.show_github_issues
155
167
  FastlaneCore::CrashReporter.report_crash(exception: e)
156
168
  display_user_error!(e, e.message)
@@ -247,6 +259,7 @@ module Commander
247
259
  reraise_formatted!(e, message)
248
260
  else
249
261
  # without stack trace
262
+ action_completed(@program[:name], status: FastlaneCore::ActionCompletionStatus::USER_ERROR, exception: e)
250
263
  abort "\n[!] #{message}".red
251
264
  end
252
265
  end
@@ -2,8 +2,7 @@ require 'excon'
2
2
  require 'digest'
3
3
 
4
4
  require 'fastlane_core/update_checker/changelog'
5
- require 'fastlane_core/ios_app_identifier_guesser'
6
- require 'fastlane_core/android_package_name_guesser'
5
+ require 'fastlane_core/analytics/app_identifier_guesser'
7
6
 
8
7
  module FastlaneCore
9
8
  # Verifies, the user runs the latest version of this gem
@@ -121,64 +120,11 @@ module FastlaneCore
121
120
  "https://rubygems.org/api/v1/gems/#{gem_name}.json"
122
121
  end
123
122
 
124
- # (optional) Returns the app identifier for the current tool
125
- def self.ios_app_identifier(args)
126
- return FastlaneCore::IOSAppIdentifierGuesser.guess_app_identifier(args)
127
- rescue
128
- nil # we don't want this method to cause a crash
129
- end
130
-
131
- # (optional) Returns the app identifier for the current tool
132
- # supply and screengrab use different param names and env variable patterns so we have to special case here
133
- # example:
134
- # fastlane supply --skip_upload_screenshots -a beta -p com.test.app should return com.test.app
135
- # screengrab -a com.test.app should return com.test.app
136
- def self.android_app_identifier(args, gem_name)
137
- app_identifier = FastlaneCore::AndroidPackageNameGuesser.guess_package_name(gem_name, args)
138
-
139
- # Add Android prefix to prevent collisions if there is an iOS app with the same identifier
140
- app_identifier ? "android_project_#{app_identifier}" : nil
141
- rescue
142
- nil # we don't want this method to cause a crash
143
- end
144
-
145
- # To not count the same projects multiple time for the number of launches
146
- # Learn more at https://github.com/fastlane/fastlane#metrics
147
- # Use the `FASTLANE_OPT_OUT_USAGE` variable to opt out
148
- # The resulting value is e.g. ce12f8371df11ef6097a83bdf2303e4357d6f5040acc4f76019489fa5deeae0d
149
- def self.p_hash(args, gem_name)
150
- return nil if FastlaneCore::Env.truthy?("FASTLANE_OPT_OUT_USAGE")
151
- require 'credentials_manager'
152
-
153
- app_identifier = app_id(args, gem_name)
154
-
155
- if app_identifier
156
- return Digest::SHA256.hexdigest("p#{app_identifier}fastlan3_SAlt") # hashed + salted the bundle identifier
157
- end
158
-
159
- return nil
160
- rescue
161
- return nil
162
- end
163
-
164
- def self.app_id(args, gem_name)
165
- # check if this is an android project first because some of the same params exist for iOS and Android tools
166
- app_identifier = android_app_identifier(args, gem_name)
167
- @platform = nil # since have a state in-between runs
168
- if app_identifier
169
- @platform = :android
170
- else
171
- app_identifier = ios_app_identifier(args)
172
- @platform = :ios if app_identifier
173
- end
174
- return app_identifier
175
- end
176
-
177
123
  def self.send_launch_analytic_events_for(gem_name)
178
124
  return if FastlaneCore::Env.truthy?("FASTLANE_OPT_OUT_USAGE")
179
-
180
125
  ci = Helper.is_ci?.to_s
181
- project_hash = p_hash(ARGV, gem_name)
126
+ app_id_guesser = FastlaneCore::AppIdentifierGuesser.new(args: ARGV, gem_name: gem_name)
127
+ project_hash = app_id_guesser.p_hash
182
128
  p_hash = project_hash if project_hash
183
129
  platform = @platform if @platform # this has to be called after `p_hash`
184
130
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.62.0.beta.20171016010004
4
+ version: 2.62.0.beta.20171017010003
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Krause
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
- date: 2017-10-16 00:00:00.000000000 Z
18
+ date: 2017-10-17 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: slack-notifier
@@ -1171,6 +1171,12 @@ files:
1171
1171
  - fastlane_core/README.md
1172
1172
  - fastlane_core/lib/assets/XMLTemplate.xml.erb
1173
1173
  - fastlane_core/lib/fastlane_core.rb
1174
+ - fastlane_core/lib/fastlane_core/analytics/action_completion_context.rb
1175
+ - fastlane_core/lib/fastlane_core/analytics/action_launch_context.rb
1176
+ - fastlane_core/lib/fastlane_core/analytics/analytics_event_builder.rb
1177
+ - fastlane_core/lib/fastlane_core/analytics/analytics_ingester_client.rb
1178
+ - fastlane_core/lib/fastlane_core/analytics/analytics_session.rb
1179
+ - fastlane_core/lib/fastlane_core/analytics/app_identifier_guesser.rb
1174
1180
  - fastlane_core/lib/fastlane_core/android_package_name_guesser.rb
1175
1181
  - fastlane_core/lib/fastlane_core/build_watcher.rb
1176
1182
  - fastlane_core/lib/fastlane_core/cert_checker.rb