sigh 0.5.2 → 0.6.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: 8b585780730eaef47020d53ae0478b5991f289dd
4
- data.tar.gz: ea30fb8b855256d7f4161902678d4154c5c5d5a3
3
+ metadata.gz: ab5bb66a972ec8b64c52d5ea5ae1b285c51f08f5
4
+ data.tar.gz: cb417be836c696568ad39438c1c553edacf7e653
5
5
  SHA512:
6
- metadata.gz: 48e286ab52ba07fcc9aceadd6c889973c7ddedd82376d23ea4ebb1f46e279c46f9a9237745203694f528bdd3eddd031e38a6eac79a4ca01566f38d81f74c50b6
7
- data.tar.gz: 2c323e4f2ae7f1055cec978229fbea421b07c806f0cbf7b3e42c143cf7c4eaaeeba9daf14c1d8502d80e48df4043fcc39a58af5c0691941fe18c12e4d8441dbc
6
+ metadata.gz: 36aea2553f3c24ac3638dcdf03a0ef989750fcd5a1a62304980e3582ec9120b3d21d174e633784cbe7c28bea9076c0607a11ebc17a2899146eed6ff3fbca6b11
7
+ data.tar.gz: 01f113d0f47e115cd554b04ead4842e416536bbf0cbdd377dc8553b81d6a6cb980e3110a77d19d148837059a03c4ee14900c377b173460a441fc59de5cd8312d
data/README.md CHANGED
@@ -51,6 +51,9 @@ Special thanks to [Matthias Tretter](https://twitter.com/myell0w) for coming up
51
51
 
52
52
  <h5 align="center"><code>sigh</code> is part of <a href="https://fastlane.tools">fastlane</a>: connect all deployment tools into one streamlined workflow.</h5>
53
53
 
54
+ ### spaceship version
55
+
56
+ If you're feeling adventurous and want to test the new `sigh` beta with [spaceship](https://spaceship.airforce), update using `sudo gem update sigh --pre`. More information in the [release notes](https://github.com/KrauseFx/sigh/releases/tag/1.0.0.beta5).
54
57
 
55
58
  # Features
56
59
 
@@ -175,6 +178,8 @@ Choose signing certificate to use:
175
178
  - `SIGH_CERTIFICATE_ID` (The ID of the certificate)
176
179
  - `SIGH_CERTIFICATE_EXPIRE_DATE` (The expire date of the certificate)
177
180
 
181
+ As always, run `sigh --help` to get a list of all variables.
182
+
178
183
  If you're using [cert](https://github.com/KrauseFx/cert) in combination with [fastlane](https://github.com/KrauseFx/fastlane) the signing certificate will automatically be selected for you. (make sure to run `cert` before `sigh`)
179
184
 
180
185
  `sigh` will store the `UDID` of the generated provisioning profile in the environment: `SIGH_UDID`.
data/lib/sigh.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'sigh/version'
2
2
  require 'sigh/dependency_checker'
3
- require 'sigh/developer_center'
4
3
  require 'sigh/resign'
5
4
  require 'fastlane_core'
6
5
 
data/lib/sigh/manager.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  require 'plist'
2
+ require 'sigh/spaceship/runner'
2
3
 
3
4
  module Sigh
4
5
  class Manager
5
6
  def self.start
6
- path = Sigh::DeveloperCenter.new.run
7
+ start = Time.now
8
+ path = Sigh::Runner.new.run
7
9
 
8
10
  return nil unless path
9
11
 
@@ -38,7 +40,7 @@ module Sigh
38
40
  (FileUtils.copy profile, destination rescue nil) # if the directory doesn't exist yet
39
41
 
40
42
  if File.exists? destination
41
- Helper.log.info "Profile installed at \"#{destination}\""
43
+ Helper.log.info "Profile successfully installed".green
42
44
  else
43
45
  raise "Failed installation of provisioning profile at location: #{destination}".red
44
46
  end
data/lib/sigh/options.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'fastlane_core'
2
+ require 'credentials_manager'
2
3
 
3
4
  module Sigh
4
5
  class Options
@@ -22,7 +23,7 @@ module Sigh
22
23
  default_value: false),
23
24
  FastlaneCore::ConfigItem.new(key: :force,
24
25
  env_name: "SIGH_FORCE",
25
- description: "Renew non-development provisioning profiles regardless of its state",
26
+ description: "Renew provisioning profiles regardless of its state",
26
27
  is_string: false,
27
28
  default_value: false),
28
29
  FastlaneCore::ConfigItem.new(key: :app_identifier,
@@ -34,7 +35,7 @@ module Sigh
34
35
  short_option: "-u",
35
36
  env_name: "SIGH_USERNAME",
36
37
  description: "Your Apple ID Username",
37
- default_value: CredentialsManager::AppfileConfig.try_fetch_value(:apple_id),
38
+ default_value: ENV["DELIVER_USER"] || CredentialsManager::AppfileConfig.try_fetch_value(:apple_id),
38
39
  verify_block: Proc.new do |value|
39
40
  CredentialsManager::PasswordManager.shared_manager(value)
40
41
  end),
@@ -43,9 +44,19 @@ module Sigh
43
44
  env_name: "SIGH_TEAM_ID",
44
45
  description: "The ID of your team if you're in multiple teams",
45
46
  optional: true,
47
+ default_value: CredentialsManager::AppfileConfig.try_fetch_value(:team_id),
46
48
  verify_block: Proc.new do |value|
47
49
  ENV["FASTLANE_TEAM_ID"] = value
48
50
  end),
51
+ FastlaneCore::ConfigItem.new(key: :team_name,
52
+ short_option: "-l",
53
+ env_name: "SIGH_TEAM_NAME",
54
+ description: "The name of your team if you're in multiple teams",
55
+ optional: true,
56
+ default_value: CredentialsManager::AppfileConfig.try_fetch_value(:team_name),
57
+ verify_block: Proc.new do |value|
58
+ ENV["FASTLANE_TEAM_NAME"] = value
59
+ end),
49
60
  FastlaneCore::ConfigItem.new(key: :provisioning_name,
50
61
  short_option: "-n",
51
62
  env_name: "SIGH_PROVISIONING_PROFILE_NAME",
@@ -62,7 +73,7 @@ module Sigh
62
73
  FastlaneCore::ConfigItem.new(key: :cert_id,
63
74
  short_option: "-i",
64
75
  env_name: "SIGH_CERTIFICATE_ID",
65
- description: "The ID of the certificate to use",
76
+ description: "The ID of the code signing certificate to use (e.g. 78ADL6LVAA) ",
66
77
  optional: true),
67
78
  FastlaneCore::ConfigItem.new(key: :cert_owner_name,
68
79
  short_option: "-c",
@@ -82,6 +93,7 @@ module Sigh
82
93
  verify_block: Proc.new do |value|
83
94
  raise "The output name must end with .mobileprovision".red unless value.end_with?".mobileprovision"
84
95
  end)
96
+
85
97
  ]
86
98
  end
87
99
  end
@@ -5,7 +5,7 @@ module Sigh
5
5
  def self.run(path)
6
6
  plist = Plist::parse_xml(`security cms -D -i '#{path}'`)
7
7
  if plist.count > 10
8
- Helper.log.info("Provisioning profile of app '#{plist['AppIDName']}' with the name '#{plist['Name']}' successfully generated and analysed.".green)
8
+ Helper.log.info("Provisioning profile of app '#{plist['AppIDName']}' with the name '#{plist['Name']}' successfully analysed.".green)
9
9
  return plist["UUID"]
10
10
  else
11
11
  Helper.log.error("Error parsing provisioning profile at path '#{path}'".red)
data/lib/sigh/resign.rb CHANGED
@@ -33,7 +33,14 @@ module Sigh
33
33
  puts command.magenta
34
34
  output = `#{command}`
35
35
  puts output
36
- if output.include?('Assuming Distribution Identity')
36
+
37
+ if signing_identity =~ /^iPhone Developer:*/
38
+ ptn = 'Assuming Development Identity'
39
+ else
40
+ ptn = 'Assuming Distribution Identity'
41
+ end
42
+
43
+ if output.include?(ptn)
37
44
  Helper.log.info "Successfully signed #{ipa}!".green
38
45
  true
39
46
  else
@@ -0,0 +1,144 @@
1
+ require 'spaceship'
2
+
3
+ module Sigh
4
+ class Runner
5
+ attr_accessor :spaceship
6
+
7
+ # Uses the spaceship to create or download a provisioning profile
8
+ # returns the path the newly created provisioning profile (in /tmp usually)
9
+ def run
10
+ Helper.log.info "Starting login"
11
+ Spaceship.login(Sigh.config[:username], nil)
12
+ Spaceship.select_team
13
+ Helper.log.info "Successfully logged in"
14
+
15
+ profiles = fetch_profiles # download the profile if it's there
16
+
17
+ if profiles.count > 0
18
+ Helper.log.info "Found #{profiles.count} matching profile(s)".yellow
19
+ profile = profiles.first
20
+
21
+ if Sigh.config[:force]
22
+ unless profile_type == Spaceship.provisioning_profile::AppStore
23
+ Helper.log.info "Updating the profile to include all devices".yellow
24
+ profile.devices = Spaceship.device.all
25
+ else
26
+ Helper.log.info "Updating the provisioning profile".yellow
27
+ end
28
+
29
+ profile = profile.update! # assign it, as it's a new profile
30
+ end
31
+ else
32
+ Helper.log.info "No existing profiles found, creating a new one for you".yellow
33
+ profile = create_profile!
34
+ end
35
+
36
+ raise "Something went wrong fetching the latest profile".red unless profile
37
+
38
+ path = download_profile(profile)
39
+ store_provisioning_id_in_environment(path)
40
+
41
+ return path
42
+ end
43
+
44
+ # The kind of provisioning profile we're interested in
45
+ def profile_type
46
+ return @profile_type if @profile_type
47
+
48
+ @profile_type = Spaceship.provisioning_profile.app_store
49
+ @profile_type = Spaceship.provisioning_profile.ad_hoc if Sigh.config[:adhoc]
50
+ @profile_type = Spaceship.provisioning_profile.development if Sigh.config[:development]
51
+ @profile_type = Spaceship.provisioning_profile.in_house if Spaceship.client.in_house?
52
+
53
+ @profile_type
54
+ end
55
+
56
+ # Fetches a profile matching the user's search requirements
57
+ def fetch_profiles
58
+ profile_type.find_by_bundle_id(Sigh.config[:app_identifier])
59
+ end
60
+
61
+ # Create a new profile and return it
62
+ def create_profile!
63
+ cert = certificate_to_use
64
+ bundle_id = Sigh.config[:app_identifier]
65
+ name = Sigh.config[:provisioning_name] || [bundle_id, profile_type.pretty_type].join(' ')
66
+
67
+ if Spaceship.provisioning_profile.all.find { |p| p.name == name }
68
+ Helper.log.error "The name '#{name}' is already taken, using another one."
69
+ name += " #{Time.now.to_i}"
70
+ end
71
+
72
+ Helper.log.info "Creating new provisioning profile for '#{Sigh.config[:app_identifier]}' with name '#{name}'".yellow
73
+ profile = profile_type.create!(name: name,
74
+ bundle_id: bundle_id,
75
+ certificate: cert)
76
+ profile
77
+ end
78
+
79
+
80
+ # Certificate to use based on the current distribution mode
81
+ def certificate_to_use
82
+ if profile_type == Spaceship.provisioning_profile.Development
83
+ certificates = Spaceship.certificate.development.all
84
+ elsif profile_type == Spaceship.provisioning_profile.InHouse
85
+ certificates = Spaceship.certificate.in_house.all
86
+ else
87
+ certificates = Spaceship.certificate.production.all # Ad hoc or App Store
88
+ end
89
+
90
+ # Filter them
91
+ certificates = certificates.find_all do |c|
92
+ if Sigh.config[:cert_id]
93
+ next unless (c.id == Sigh.config[:cert_id].strip)
94
+ end
95
+
96
+ if Sigh.config[:cert_owner_name]
97
+ next unless (c.owner_name.strip == Sigh.config[:cert_owner_name].strip)
98
+ end
99
+
100
+ true
101
+ end
102
+
103
+ if certificates.count > 1
104
+ Helper.log.info "Found more than one code signing identity. Choosing the first one. Check out `sigh --help` to see all available options.".yellow
105
+ Helper.log.info "Available Code Signing Identities for current filters:".green
106
+ certificates.each do |c|
107
+ Helper.log.info ("\t- Name: " + c.owner_name + " - ID: " + c.id + " - Expires: " + c.expires.strftime("%d/%m/%Y")).green
108
+ end
109
+ end
110
+
111
+ if certificates.count == 0
112
+ filters = ""
113
+ filters << "Owner Name: '#{Sigh.config[:cert_owner_name]}' " if Sigh.config[:cert_owner_name]
114
+ filters << "Certificate ID: '#{Sigh.config[:cert_id]}' " if Sigh.config[:cert_id]
115
+ Helper.log.info "No certificates for filter: #{filters}".yellow if filters.length > 0
116
+ raise "Could not find a matching code signing identity for #{profile_type}. You can use cert to generate one (https://github.com/fastlane/cert)".red
117
+ end
118
+
119
+ return certificates.first
120
+ end
121
+
122
+ # Downloads and stores the provisioning profile
123
+ def download_profile(profile)
124
+ Helper.log.info "Downloading provisioning profile...".yellow
125
+ profile_name ||= "#{profile.class.pretty_type}_#{Sigh.config[:app_identifier]}.mobileprovision" # default name
126
+ profile_name += '.mobileprovision' unless profile_name.include?'mobileprovision'
127
+
128
+ output_path = File.join('/tmp', profile_name)
129
+ dataWritten = File.open(output_path, "wb") do |f|
130
+ f.write(profile.download)
131
+ end
132
+
133
+ Helper.log.info "Successfully downloaded provisioning profile...".green
134
+ return output_path
135
+ end
136
+
137
+ # Store the profile ID into the environment
138
+ def store_provisioning_id_in_environment(path)
139
+ require 'sigh/profile_analyser'
140
+ udid = Sigh::ProfileAnalyser.run(path)
141
+ ENV["SIGH_UDID"] = udid if udid
142
+ end
143
+ end
144
+ end
data/lib/sigh/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sigh
2
- VERSION = "0.5.2"
2
+ VERSION = "0.6.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sigh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Krause
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-22 00:00:00.000000000 Z
11
+ date: 2015-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fastlane_core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.7.2
19
+ version: 0.7.6
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.7.2
26
+ version: 0.7.6
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: plist
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 3.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: spaceship
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.0.8
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.8
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -151,13 +165,12 @@ files:
151
165
  - lib/assets/resign.sh
152
166
  - lib/sigh.rb
153
167
  - lib/sigh/dependency_checker.rb
154
- - lib/sigh/developer_center.rb
155
- - lib/sigh/developer_center_signing.rb
156
168
  - lib/sigh/local_manage.rb
157
169
  - lib/sigh/manager.rb
158
170
  - lib/sigh/options.rb
159
171
  - lib/sigh/profile_analyser.rb
160
172
  - lib/sigh/resign.rb
173
+ - lib/sigh/spaceship/runner.rb
161
174
  - lib/sigh/version.rb
162
175
  homepage: https://fastlane.tools
163
176
  licenses:
@@ -179,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
192
  version: '0'
180
193
  requirements: []
181
194
  rubyforge_project:
182
- rubygems_version: 2.2.2
195
+ rubygems_version: 2.4.7
183
196
  signing_key:
184
197
  specification_version: 4
185
198
  summary: Because you would rather spend your time building stuff than fighting provisioning
@@ -1,292 +0,0 @@
1
- require 'fastlane_core/developer_center/developer_center'
2
- require 'sigh/developer_center_signing'
3
-
4
- module Sigh
5
- class DeveloperCenter < FastlaneCore::DeveloperCenter
6
- # Types of certificates
7
- APPSTORE = "AppStore"
8
- ADHOC = "AdHoc"
9
- DEVELOPMENT = "Development"
10
-
11
- PROFILES_URL_DEV = "https://developer.apple.com/account/ios/profile/profileList.action?type=limited"
12
-
13
- def run
14
- @type = Sigh::DeveloperCenter::APPSTORE
15
- @type = Sigh::DeveloperCenter::ADHOC if Sigh.config[:adhoc]
16
- @type = Sigh::DeveloperCenter::DEVELOPMENT if Sigh.config[:development]
17
-
18
- cert = maintain_app_certificate # create/download the certificate
19
-
20
- if @type == APPSTORE # both enterprise and App Store
21
- type_name = "Distribution"
22
- elsif @type == ADHOC
23
- type_name = "AdHoc"
24
- else
25
- type_name = "Development"
26
- end
27
- cert_name ||= "#{type_name}_#{Sigh.config[:app_identifier]}.mobileprovision" # default name
28
- cert_name += '.mobileprovision' unless cert_name.include?'mobileprovision'
29
-
30
- output_path = File.join(TMP_FOLDER, cert_name)
31
- dataWritten = File.open(output_path, "wb") do |f|
32
- f.write(cert)
33
- end
34
-
35
- store_provisioning_id_in_environment(output_path)
36
-
37
- return output_path
38
- end
39
-
40
- def store_provisioning_id_in_environment(path)
41
- require 'sigh/profile_analyser'
42
- udid = Sigh::ProfileAnalyser.run(path)
43
- ENV["SIGH_UDID"] = udid if udid
44
- end
45
-
46
- def maintain_app_certificate(force = nil)
47
- force = Sigh.config[:force] if (force == nil)
48
- begin
49
- if @type == DEVELOPMENT
50
- visit PROFILES_URL_DEV
51
- else
52
- visit PROFILES_URL
53
- end
54
-
55
- @list_certs_url = wait_for_variable('profileDataURL')
56
- # list_certs_url will look like this: "https://developer.apple.com/services-account/..../account/ios/profile/listProvisioningProfiles.action?content-type=application/x-www-form-urlencoded&accept=application/json&requestId=id&userLocale=en_US&teamId=xy&includeInactiveProfiles=true&onlyCountLists=true"
57
- Helper.log.info "Fetching all available provisioning profiles..."
58
-
59
- has_all_profiles = false
60
- page_index = 1
61
- page_size = 500
62
-
63
- until has_all_profiles do
64
- bundle_id = Sigh.config[:app_identifier]
65
-
66
- certs = post_ajax(@list_certs_url, "{pageNumber: #{page_index}, pageSize: #{page_size}, sort: 'name%3dasc', search: ''}")
67
-
68
- if certs
69
- profile_name = Sigh.config[:provisioning_name]
70
-
71
- profile_count = certs['provisioningProfiles'].count
72
-
73
- Helper.log.info "Checking if profile is available. (#{profile_count} profiles found on page #{page_index})"
74
- required_cert_types = (@type == DEVELOPMENT ? ['iOS Development'] : ['iOS Distribution', 'iOS UniversalDistribution'])
75
- certs['provisioningProfiles'].each do |current_cert|
76
- next unless required_cert_types.include?(current_cert['type'])
77
-
78
- details = profile_details(current_cert['provisioningProfileId'])
79
-
80
- if details['provisioningProfile']['appId']['identifier'] == bundle_id
81
-
82
- next if profile_name && details['provisioningProfile']['name'] != profile_name
83
-
84
- # that's an Ad Hoc profile. I didn't find a better way to detect if it's one ... skipping it
85
- next if @type == APPSTORE && details['provisioningProfile']['deviceCount'] > 0
86
-
87
- # that's an App Store profile ... skipping it
88
- next if @type != APPSTORE && details['provisioningProfile']['deviceCount'] == 0
89
-
90
- # We found the correct certificate
91
- if force
92
- renew_profile(current_cert['provisioningProfileId']) # This one needs to be forcefully renewed
93
- return maintain_app_certificate(false) # recursive
94
- elsif current_cert['status'] == 'Active'
95
- return download_profile(details['provisioningProfile']['provisioningProfileId']) # this one is already finished. Just download it.
96
- elsif ['Expired', 'Invalid'].include? current_cert['status']
97
- # Broken profile
98
- begin
99
- renew_profile(current_cert['provisioningProfileId']) # This one needs to be renewed
100
- return maintain_app_certificate(false) # recursive
101
- rescue
102
- # Something went wrong, just create a new one instead
103
- end
104
- end
105
-
106
- break
107
- end
108
- end
109
-
110
- if page_size <= profile_count
111
- page_index += 1
112
- else
113
- has_all_profiles = true
114
- end
115
- end
116
- end
117
-
118
- Helper.log.info "Could not find existing profile. Trying to create a new one."
119
- # Certificate does not exist yet, we need to create a new one
120
- create_profile
121
- # After creating the profile, we need to download it
122
- return maintain_app_certificate(false) # recursive
123
-
124
- rescue => ex
125
- error_occured(ex)
126
- end
127
- end
128
-
129
- def create_profile
130
- app_identifier = Sigh.config[:app_identifier]
131
- Helper.log.info "Creating new profile for app '#{app_identifier}' for type '#{@type}'.".yellow
132
- certificates = code_signing_certificates(@type)
133
-
134
- create_url = "https://developer.apple.com/account/ios/profile/profileCreate.action"
135
- visit create_url
136
-
137
- # 1) Select the profile type (AppStore, Adhoc)
138
- enterprise = false
139
-
140
- begin
141
- wait_for_elements('#type-production')
142
- rescue => ex
143
- wait_for_elements('#type-inhouse') # enterprise accounts
144
- enterprise = true
145
- end
146
-
147
- value = enterprise ? 'inhouse' : 'store'
148
- value = 'limited' if @type == DEVELOPMENT
149
- value = 'adhoc' if @type == ADHOC
150
-
151
- first(:xpath, "//input[@type='radio' and @value='#{value}']").click
152
- click_next
153
-
154
- # 2) Select the App ID
155
- sleep 1 while !page.has_content? "Select App ID"
156
- # example: <option value="RGAWZGXSY4">ABP (5A997XSHK2.net.sunapps.34)</option>
157
- identifiers = all(:xpath, "//option[contains(text(), '.#{app_identifier})')]")
158
- if identifiers.count == 0
159
- puts "Couldn't find App ID '#{app_identifier}'\nonly found the following bundle identifiers:".red
160
- all(:xpath, "//option").each do |current|
161
- puts "\t- #{current.text}".yellow
162
- end
163
- raise "Could not find App ID '#{app_identifier}'.".red
164
- else
165
- identifiers.first.select_option
166
- end
167
- click_next
168
-
169
- # 3) Select the certificate
170
- sleep 1 while !page.has_content? "Select certificates"
171
- sleep 3
172
- Helper.log.info "Using certificates: #{certificates.map { |c| "#{c['ownerName']} (#{c['certificateId']})" } }"
173
-
174
- # example: <input type="radio" name="certificateIds" class="validate" value="[XC5PH8D47H]"> (production)
175
-
176
- clicked = false
177
- certificates.each do |cert|
178
- cert_id = cert['certificateId']
179
- input = if @type == DEVELOPMENT
180
- # development uses a checkbox and has no [] around the value
181
- first(:xpath, "//input[@type='checkbox' and @value='#{cert_id}']")
182
- else
183
- break if clicked
184
- # production uses radio and has a [] around the value
185
- first(:xpath, "//input[@type='radio' and @value='[#{cert_id}]']")
186
- end
187
- if input
188
- input.click
189
- clicked = true
190
- end
191
- end
192
-
193
- if !clicked
194
- raise "Could not find certificate in the list of available certificates."
195
- end
196
- click_next
197
-
198
- if @type != APPSTORE
199
- # 4) Devices selection
200
- wait_for_elements('.selectAll.column')
201
- sleep 3
202
-
203
- first(:xpath, "//div[@class='selectAll column']/input").click # select all the devices
204
- click_next
205
- end
206
-
207
- # 5) Choose a profile name
208
- wait_for_elements('.distributionType')
209
- profile_name = Sigh.config[:provisioning_name]
210
- profile_name ||= [app_identifier, @type].join(' ')
211
- fill_in "provisioningProfileName", with: profile_name
212
- click_next
213
-
214
- if page.has_content?"Multiple profiles found with the name"
215
- fill_in "provisioningProfileName", with: (profile_name + " sigh")
216
- click_next
217
- end
218
-
219
- wait_for_elements('.row-details')
220
- end
221
-
222
- def renew_profile(profile_id)
223
- certificate = code_signing_certificates(@type).first
224
-
225
- details_url = "https://developer.apple.com/account/ios/profile/profileEdit.action?type=&provisioningProfileId=#{profile_id}"
226
- Helper.log.info "Renewing provisioning profile '#{profile_id}' using URL '#{details_url}'"
227
- visit details_url
228
-
229
- Helper.log.info "Using certificate ID '#{certificate['certificateId']}' from '#{certificate['ownerName']}'"
230
- wait_for_elements('.selectCertificates')
231
-
232
- certs = all(:xpath, "//input[@type='radio' and @value='#{certificate["certificateId"]}']")
233
- if certs.count == 1
234
- certs.first.click
235
-
236
- if @type != APPSTORE
237
- # Add all devices
238
- wait_for_elements('.selectAll.column')
239
- sleep 3
240
- unless first(:xpath, "//div[@class='selectAll column']/input")["checked"]
241
- first(:xpath, "//div[@class='selectAll column']/input").click # select all the devices
242
- end
243
- end
244
-
245
- click_next
246
-
247
- wait_for_elements('.row-details')
248
- click_on "Done"
249
- else
250
- if @type != APPSTORE
251
- # Add all devices
252
- wait_for_elements('.selectAll.column')
253
- sleep 3
254
- unless all(:xpath, "//div[@class='selectAll column']/input").last["checked"]
255
- all(:xpath, "//div[@class='selectAll column']/input").last.click # select all the devices
256
- end
257
- click_next
258
-
259
- wait_for_elements('.row-details')
260
- click_on "Done"
261
- else
262
- Helper.log.info "Looking for certificate: #{certificate}."
263
- raise "Could not find certificate in the list of available certificates."
264
- end
265
- end
266
- end
267
-
268
- def download_profile(profile_id)
269
- download_cert_url = "/account/ios/profile/profileContentDownload.action?displayId=#{profile_id}"
270
-
271
- return download_file(download_cert_url)
272
- end
273
-
274
-
275
- private
276
- def profile_details(profile_id)
277
- # We need to build the URL to get the App ID for a specific certificate
278
- current_profile_url = @list_certs_url.gsub('listProvisioningProfiles', 'getProvisioningProfile')
279
- current_profile_url += "&provisioningProfileId=#{profile_id}"
280
- # Helper.log.debug "Fetching URL: '#{current_profile_url}'"
281
-
282
- result = post_ajax(current_profile_url)
283
- # Example response, see bottom of file
284
-
285
- if result['resultCode'] == 0
286
- return result
287
- else
288
- raise "Error fetching details for provisioning profile '#{profile_id}'".red
289
- end
290
- end
291
- end
292
- end
@@ -1,88 +0,0 @@
1
- module Sigh
2
- class DeveloperCenter < FastlaneCore::DeveloperCenter
3
- # Returns a array of hashes, that contains information about the iOS certificate
4
- # @example
5
- # [{"certRequestId"=>"B23Q2P396B",
6
- # "name"=>"SunApps GmbH",
7
- # "statusString"=>"Issued",
8
- # "expirationDate"=>"2015-11-25T22:45:50Z",
9
- # "expirationDateString"=>"Nov 25, 2015",
10
- # "ownerType"=>"team",
11
- # "ownerName"=>"SunApps GmbH",
12
- # "ownerId"=>"....",
13
- # "canDownload"=>true,
14
- # "canRevoke"=>true,
15
- # "certificateId"=>"....",
16
- # "certificateStatusCode"=>0,
17
- # "certRequestStatusCode"=>4,
18
- # "certificateTypeDisplayId"=>"...",
19
- # "serialNum"=>"....",
20
- # "typeString"=>"iOS Distribution"},
21
- # {another sertificate...}]
22
- def code_signing_certificates(type)
23
- certs_url = "https://developer.apple.com/account/ios/certificate/certificateList.action?type="
24
- certs_url << (type == DEVELOPMENT ? 'development' : 'distribution')
25
- visit certs_url
26
-
27
- certificateDataURL = wait_for_variable('certificateDataURL')
28
- certificateRequestTypes = wait_for_variable('certificateRequestTypes')
29
- certificateStatuses = wait_for_variable('certificateStatuses')
30
-
31
- url = [certificateDataURL, certificateRequestTypes, certificateStatuses].join('')
32
-
33
- # https://developer.apple.com/services-account/.../account/ios/certificate/listCertRequests.action?content-type=application/x-www-form-urlencoded&accept=application/json&requestId=...&userLocale=en_US&teamId=...&types=...&status=4&certificateStatus=0&type=distribution
34
-
35
- certs = post_ajax(url, "{pageNumber: 1, pageSize: 500, sort: 'name%3dasc'}")['certRequests']
36
-
37
- ret_certs = []
38
-
39
- # Select certificate
40
- certificate_name = Sigh.config[:cert_owner_name]
41
- cert_date = Sigh.config[:cert_date]
42
- cert_id = Sigh.config[:cert_id]
43
-
44
- # The other profiles are push profiles
45
- certificate_type = type == DEVELOPMENT ? 'iOS Development' : 'iOS Distribution'
46
-
47
- # New profiles first
48
- certs.sort! do |a, b|
49
- Time.parse(b['expirationDate']) <=> Time.parse(a['expirationDate'])
50
- end
51
-
52
- certs.each do |current_cert|
53
- next unless current_cert['typeString'] == certificate_type
54
-
55
- if cert_date || certificate_name || cert_id
56
- if current_cert['expirationDateString'] == cert_date
57
- Helper.log.info "Certificate ID '#{current_cert['certificateId']}' with expiry date '#{current_cert['expirationDateString']}' located".green
58
- ret_certs << current_cert
59
- end
60
-
61
- if current_cert['name'] == certificate_name
62
- Helper.log.info "Certificate ID '#{current_cert['certificateId']}' with name '#{certificate_name}' located".green
63
- ret_certs << current_cert
64
- end
65
-
66
- if current_cert['certificateId'] == cert_id
67
- Helper.log.info "Certificate ID '#{current_cert['certificateId']}' with name '#{current_cert['name']}' located".green
68
- ret_certs << current_cert
69
- end
70
- else
71
- ret_certs << current_cert
72
- end
73
- end
74
-
75
- return ret_certs unless ret_certs.empty?
76
-
77
- predicates = []
78
- predicates << "name: #{certificate_name}" if certificate_name
79
- predicates << "expiry date: #{cert_date}" if cert_date
80
- predicates << "certificate ID: #{cert_id}" if cert_id
81
- predicates << "type: #{(type == DEVELOPMENT ? 'development' : 'distribution')}"
82
-
83
- predicates_str = " with #{predicates.join(', ')}"
84
-
85
- raise "Could not find a Certificate#{predicates_str}. Please open #{current_url} and make sure you have a signing profile created, which matches the given filters".red
86
- end
87
- end
88
- end