Class: FastlaneCore::UpdateChecker

Inherits:
Object
  • Object
show all
Defined in:
lib/fastlane_core/update_checker/update_checker.rb

Overview

Verifies, the user runs the latest version of this gem

Constant Summary collapse

UPDATE_URL =

This web service is fully open source: github.com/fastlane/refresher

"https://fastlane-refresher.herokuapp.com/"

Class Method Summary collapse

Class Method Details

.android_app_identifier(args, gem_name) ⇒ Object

(optional) Returns the app identifier for the current tool supply and screengrab use different param names and env variable patterns so we have to special case here example:

supply --skip_upload_screenshots -a beta -p com.test.app should return com.test.app
screengrab -a com.test.app should return com.test.app


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 137

def self.android_app_identifier(args, gem_name)
  app_identifier = nil
  # args example: ["-a", "com.krausefx.app"]
  args.each_with_index do |current, index|
    if android_app_identifier_arg?(gem_name, current)
      app_identifier = args[index + 1] if args.count > index
      break
    end
  end

  app_identifier ||= ENV["SUPPLY_PACKAGE_NAME"] if ENV["SUPPLY_PACKAGE_NAME"]
  app_identifier ||= ENV["SCREENGRAB_APP_PACKAGE_NAME"] if ENV["SCREENGRAB_APP_PACKAGE_NAME"]
  app_identifier ||= CredentialsManager::AppfileConfig.try_fetch_value(:package_name)

  # Add Android prefix to prevent collisions if there is an iOS app with the same identifier
  app_identifier ? "android_project_#{app_identifier}" : nil
rescue
  nil # we don't want this method to cause a crash
end

.android_app_identifier_arg?(gem_name, arg) ⇒ Boolean

Returns:

  • (Boolean)


157
158
159
160
161
162
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 157

def self.android_app_identifier_arg?(gem_name, arg)
  return arg == "--package_name" ||
         arg == "--app_package_name" ||
         (arg == '-p' && gem_name == 'supply') ||
         (arg == '-a' && gem_name == 'screengrab')
end

.fetch_latest(url) ⇒ Object



101
102
103
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 101

def self.fetch_latest(url)
  JSON.parse(Excon.post(url).body).fetch("version", nil)
end

.finished_running(gem_name) ⇒ Object



105
106
107
108
109
110
111
112
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 105

def self.finished_running(gem_name)
  time = (Time.now - @start_time).to_i

  url = UPDATE_URL + "time/#{gem_name}"
  url += "?time=#{time}"
  url += "&ci=1" if Helper.is_ci?
  Excon.post(url)
end

.generate_fetch_url(gem_name) ⇒ Object

Generate the URL on the main thread (since we’re switching directory)



88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 88

def self.generate_fetch_url(gem_name)
  url = UPDATE_URL + gem_name
  params = {}
  params["ci"] = "1" if Helper.is_ci?

  project_hash = p_hash(ARGV, gem_name)
  params["p_hash"] = project_hash if project_hash
  params["platform"] = @platform if @platform # this has to be called after `p_hash`

  url += "?" + URI.encode_www_form(params) if params.count > 0
  return url
end

.ios_app_identifier(args) ⇒ Object

(optional) Returns the app identifier for the current tool



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 115

def self.ios_app_identifier(args)
  # args example: ["-a", "com.krausefx.app", "--team_id", "5AA97AAHK2"]
  args.each_with_index do |current, index|
    if current == "-a" || current == "--app_identifier"
      return args[index + 1] if args.count > index
    end
  end

  ["FASTLANE", "DELIVER", "PILOT", "PRODUCE", "PEM", "SIGH", "SNAPSHOT", "MATCH"].each do |current|
    return ENV["#{current}_APP_IDENTIFIER"] if ENV["#{current}_APP_IDENTIFIER"]
  end

  return CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
rescue
  nil # we don't want this method to cause a crash
end

.p_hash(args, gem_name) ⇒ Object

To not count the same projects multiple time for the number of launches More information: github.com/fastlane/refresher Use the ‘FASTLANE_OPT_OUT_USAGE` variable to opt out The resulting value is e.g. ce12f8371df11ef6097a83bdf2303e4357d6f5040acc4f76019489fa5deeae0d



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 168

def self.p_hash(args, gem_name)
  return nil if ENV["FASTLANE_OPT_OUT_USAGE"]
  require 'credentials_manager'

  # check if this is an android project first because some of the same params exist for iOS and Android tools
  app_identifier = android_app_identifier(args, gem_name)
  @platform = nil # since have a state in-between runs
  if app_identifier
    @platform = :android
  else
    app_identifier = ios_app_identifier(args)
    @platform = :ios if app_identifier
  end

  if app_identifier
    return Digest::SHA256.hexdigest("p#{app_identifier}fastlan3_SAlt") # hashed + salted the bundle identifier
  end

  return nil
rescue
  return nil
end

.server_resultsObject



27
28
29
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 27

def self.server_results
  @results ||= {}
end

.show_update_message(gem_name, current_version) ⇒ Object

Show a message to the user to update to a new version of fastlane (or a sub-gem) Use this method, as this will detect the current Ruby environment and show an appropriate message to the user



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 53

def self.show_update_message(gem_name, current_version)
  available = server_results[gem_name]
  puts ""
  puts '#######################################################################'.green
  if available
    puts "# #{gem_name} #{available} is available. You are on #{current_version}.".green
  else
    puts "# An update for #{gem_name} is available. You are on #{current_version}.".green
  end
  puts "# It is recommended to use the latest version.".green
  puts "# Please update using `#{self.update_command(gem_name: gem_name)}`.".green

  puts "# To see what's new, open https://github.com/fastlane/#{gem_name}/releases.".green if ENV["FASTLANE_HIDE_CHANGELOG"]

  if !Helper.bundler? && !Helper.contained_fastlane? && Random.rand(5) == 1
    # We want to show this message from time to time, if the user doesn't use bundler, nor bundled fastlane
    puts '#######################################################################'.green
    puts "# Run `sudo gem cleanup` from time to time to speed up fastlane".green
  end
  puts '#######################################################################'.green
  Changelog.show_changes(gem_name, current_version) unless ENV["FASTLANE_HIDE_CHANGELOG"]
end

.show_update_status(gem_name, current_version) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 36

def self.show_update_status(gem_name, current_version)
  fork do
    begin
      finished_running(gem_name)
    rescue
      # we don't want to show a stack trace if something goes wrong
    end
  end

  if update_available?(gem_name, current_version)
    show_update_message(gem_name, current_version)
  end
end

.start_looking_for_update(gem_name) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 12

def self.start_looking_for_update(gem_name)
  return if Helper.is_test?
  return if ENV["FASTLANE_SKIP_UPDATE_CHECK"]

  @start_time = Time.now

  url = generate_fetch_url(gem_name)
  Thread.new do
    begin
      server_results[gem_name] = fetch_latest(url)
    rescue
    end
  end
end

.update_available?(gem_name, current_version) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 31

def self.update_available?(gem_name, current_version)
  latest = server_results[gem_name]
  return (latest and Gem::Version.new(latest) > Gem::Version.new(current_version))
end

.update_command(gem_name: "fastlane") ⇒ Object

The command that the user should use to update their mac



77
78
79
80
81
82
83
84
85
# File 'lib/fastlane_core/update_checker/update_checker.rb', line 77

def self.update_command(gem_name: "fastlane")
  if Helper.bundler?
    "bundle update #{gem_name.downcase}"
  elsif Helper.contained_fastlane?
    "fastlane update_fastlane"
  else
    "sudo gem update #{gem_name.downcase}"
  end
end