Class: FastlaneCore::DeveloperCenter

Inherits:
Object
  • Object
show all
Includes:
Capybara::DSL
Defined in:
lib/fastlane_core/developer_center/developer_center.rb,
lib/fastlane_core/developer_center/developer_center_login.rb,
lib/fastlane_core/developer_center/developer_center_helper.rb

Defined Under Namespace

Classes: DeveloperCenterGeneralError, DeveloperCenterLoginError

Constant Summary collapse

DEVELOPER_CENTER_URL =
"https://developer.apple.com/devcenter/ios/index.action"
PROFILES_URL =
"https://developer.apple.com/account/ios/profile/profileList.action?type=production"
TMP_FOLDER =
"/tmp/fastlane_core/"

Instance Method Summary collapse

Constructor Details

#initializeDeveloperCenter

Returns a new instance of DeveloperCenter.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/fastlane_core/developer_center/developer_center.rb', line 28

def initialize
  FileUtils.mkdir_p TMP_FOLDER
  
  Capybara.run_server = false
  Capybara.default_driver = :poltergeist
  Capybara.javascript_driver = :poltergeist
  Capybara.current_driver = :poltergeist
  Capybara.app_host = DEVELOPER_CENTER_URL

  # Since Apple has some SSL errors, we have to configure the client properly:
  # https://github.com/ariya/phantomjs/issues/11239
  Capybara.register_driver :poltergeist do |a|
    conf = ['--debug=no', '--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1']
    Capybara::Poltergeist::Driver.new(a, {
      phantomjs: Phantomjs.path,
      phantomjs_options: conf,
      phantomjs_logger: File.open("#{TMP_FOLDER}/poltergeist_log.txt", "a"),
      js_errors: false,
      timeout: 90
    })
  end

  page.driver.headers = { "Accept-Language" => "en" }

  self.
end

Instance Method Details

#click_nextObject



28
29
30
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 28

def click_next
  wait_for_elements('.button.small.blue.right.submit').last.click
end

#download_file(url) ⇒ Object

Download a file from the dev center, by using a HTTP client. This will return the content of the file



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 6

def download_file(url)
  Helper.log.info "Downloading profile..."
  host = Capybara.current_session.current_host
  url = [host, url].join('')

  cookie_string = ""
  
  page.driver.cookies.each do |key, cookie|
    cookie_string << "#{cookie.name}=#{cookie.value};" # append all known cookies
  end
  
  data = open(url, {'Cookie' => cookie_string}).read

  raise "Something went wrong when downloading the file from the Dev Center" unless data
  Helper.log.info "Successfully downloaded provisioning profile"
  return data
end

#error_occured(ex) ⇒ Object



32
33
34
35
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 32

def error_occured(ex)
  snap
  raise ex # re-raise the error after saving the snapshot
end

#login(user = nil, password = nil) ⇒ bool

Log in a user with the given login data on the Dev Center Frontend. You don’t need to pass a username and password. It will Automatically be fetched using the CredentialsManager::PasswordManager. This method will also automatically be called when triggering other actions like #open_app_page

Parameters:

  • user (String) (defaults to: nil)

    (optional) The username/email address

  • password (String) (defaults to: nil)

    (optional) The password

Returns:

  • (bool)

    true if everything worked fine

Raises:



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/fastlane_core/developer_center/developer_center_login.rb', line 14

def (user = nil, password = nil)
  begin
    Helper.log.info "Login into iOS Developer Center"

    user ||= CredentialsManager::PasswordManager.shared_manager.username
    password ||= CredentialsManager::PasswordManager.shared_manager.password

    result = visit PROFILES_URL
    raise "Could not open Developer Center" unless result['status'] == 'success'

    # Already logged in
    select_team if current_url.include?"selectTeam.action"
    return true if (page.has_content? "Member Center" and not current_url.include?"selectTeam.action")

    (wait_for_elements(".button.blue").first.click rescue nil) # maybe already logged in

    (wait_for_elements('#accountpassword') rescue nil) # when the user is already logged in, this will raise an exception

    # Already logged in
    select_team if current_url.include?"selectTeam.action"
    return true if (page.has_content? "Member Center" and not current_url.include?"selectTeam.action")

    fill_in "accountname", with: user
    fill_in "accountpassword", with: password

    all(".button.large.blue.signin-button").first.click

    begin
      # If the user is not on multiple teams
      select_team if current_url.include?"selectTeam.action"
    rescue => ex
      Helper.log.debug ex
      raise DeveloperCenterLoginError.new("Error loggin in user #{user}. User is on multiple teams and we were unable to correctly retrieve them.")
    end

    begin
      wait_for_elements('.ios.profiles.gridList')
      visit PROFILES_URL # again, since after the login, the dev center loses the production GET value
    rescue => ex
      if page.has_content?"Getting Started"
        visit PROFILES_URL # again, since after the login, the dev center loses the production GET value
      else
        Helper.log.debug ex
        raise DeveloperCenterLoginError.new("Error logging in user #{user} with the given password. Make sure you entered them correctly.".red)
      end
    end

    Helper.log.info "Login successful"
    
    true
  rescue => ex
    error_occured(ex)
  end
end

#post_ajax(url, data = nil) ⇒ Object



24
25
26
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 24

def post_ajax(url, data = nil)
  JSON.parse(page.evaluate_script("$.ajax({type: 'POST', url: '#{url}', async: false#{data.nil? ? '' : ", data: #{data}"} })")['responseText'])
end

#select_teamObject



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/fastlane_core/developer_center/developer_center_login.rb', line 70

def select_team
  team_id = ENV["FASTLANE_TEAM_ID"] || CredentialsManager::AppfileConfig.try_fetch_value(:team_id)

  team_name = ENV["FASTLANE_TEAM_NAME"] || CredentialsManager::AppfileConfig.try_fetch_value(:team_name)

  if team_id == nil and team_name == nil
    Helper.log.info "You can store your preferred team using the environment variable `FASTLANE_TEAM_ID` or `FASTLANE_TEAM_NAME`".green
    Helper.log.info "or in your `Appfile` using `team_id 'Q2CBPJ58CA'` or `team_name 'Felix Krause'`".green
    Helper.log.info "Your ID belongs to the following teams:".green
  end
  
  available_options = []

  teams = find("div.input").all('.team-value') # Grab all the teams data
  teams.each_with_index do |val, index|
    current_team_id = '"' + val.find("input").value + '"'
    team_text = val.find(".label-primary").text
    description_text = val.find(".label-secondary").text
    description_text = "(#{description_text})" unless description_text.empty? # Include the team description if any
    index_text = (index + 1).to_s + "."

    available_options << [index_text, current_team_id, team_text, description_text].join(" ")
  end

  if team_name
    # Search for name
    found_it = false
    all("label.label-primary").each do |current|
      if current.text.downcase.gsub(/\s+/, "") == team_name.downcase.gsub(/\s+/, "")
        current.click # select the team by name
        found_it = true
      end
    end

    unless found_it
      available_teams = all("label.label-primary").collect { |a| a.text }
      raise DeveloperCenterLoginError.new("Could not find Team with name '#{team_name}'. Available Teams: #{available_teams}".red)
    end
  else
    # Search by ID/Index
    unless team_id
      puts available_options.join("\n").green
      team_index = ask("Please select the team number you would like to access: ".green)
      team_id = teams[team_index.to_i - 1].find(".radio").value
    end

    team_button = first(:xpath, "//input[@type='radio' and @value='#{team_id}']") # Select the desired team
    if team_button
      team_button.click
    else
      Helper.log.fatal "Could not find given Team. Available options: ".red
      puts available_options.join("\n").yellow
      raise DeveloperCenterLoginError.new("Error finding given team #{team_id}.".red)
    end
  end

  all(".button.large.blue.submit").first.click

  result = visit PROFILES_URL
  raise "Could not open Developer Center" unless result['status'] == 'success'
end

#snapObject



37
38
39
40
41
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 37

def snap
  path = File.expand_path("Error#{Time.now.to_i}.png")
  save_screenshot(path, :full => true)
  system("open '#{path}'") unless ENV['SIGH_DISABLE_OPEN_ERROR']
end

#valid_name_for(input) ⇒ Object



75
76
77
78
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 75

def valid_name_for(input)
  latinazed = input.to_slug.transliterate.to_s # remove accents
  latinazed.gsub(/[^0-9A-Za-z\d\s]/, '') # remove non-valid characters
end

#wait_for(method, parameter, success) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 43

def wait_for(method, parameter, success)
  counter = 0
  result = method.call(parameter)
  while !success.call(result)
    sleep 0.2

    result = method.call(parameter)

    counter += 1
    if counter > 100
      Helper.log.debug caller
      raise DeveloperCenterGeneralError.new("Couldn't find '#{parameter}' after waiting for quite some time")
    end
  end
  return result
end

#wait_for_elements(name) ⇒ Object



60
61
62
63
64
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 60

def wait_for_elements(name)
  method = Proc.new { |n| all(name) }
  success = Proc.new { |r| r.count > 0 }
  return wait_for(method, name, success)
end

#wait_for_variable(name) ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/fastlane_core/developer_center/developer_center_helper.rb', line 66

def wait_for_variable(name)
  method = Proc.new { |n|
    retval = page.html.match(/var #{n} = "(.*)"/)
    retval[1] unless retval == nil
  }
  success = Proc.new { |r| r != nil }
  return wait_for(method, name, success)
end