pem 0.3.3 → 0.3.4
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 +4 -4
- data/README.md +2 -2
- data/lib/pem.rb +6 -7
- data/lib/pem/cert_manager.rb +1 -1
- data/lib/pem/developer_center.rb +8 -185
- data/lib/pem/version.rb +1 -1
- metadata +3 -103
- data/lib/pem/helper.rb +0 -49
- data/lib/pem/update_checker.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac3066ee25047a3d83151ec0832384b64d004b51
|
4
|
+
data.tar.gz: 55e0c443e90906bd180e20d11bab3291c4560d9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb43e922dc627c97cba4805a06df6395de73e4afba158d06515d9501e8cde1019dc6aaf50085ce8f205bd544bf8bd14b8e8ec307530b5eb37e7033d5cb75938b
|
7
|
+
data.tar.gz: a690f2b0e4d4c18a9d396b6b7d003ec76f05f25bf52e7bbe3ea41bc1bbe87b95ce31eb9cc45754804e8a8abfb0e86b4bc0b51473c01a0c4c4f23e6600b9e4b14
|
data/README.md
CHANGED
@@ -50,6 +50,8 @@ Alexander Schuch ([@schuchalexander](https://twitter.com/schuchalexander)) who a
|
|
50
50
|
|
51
51
|
-------
|
52
52
|
|
53
|
+
<h5 align="center"><code>PEM</code> is part of <a href="http://fastlane.tools">fastlane</a>: connect all deployment tools into one streamlined workflow.</h5>
|
54
|
+
|
53
55
|
# Features
|
54
56
|
Well, it's actually just one: Generate the ```pem``` file for your server.
|
55
57
|
|
@@ -65,8 +67,6 @@ Make sure, you have the latest version of the Xcode command line tools installed
|
|
65
67
|
|
66
68
|
xcode-select --install
|
67
69
|
|
68
|
-
If you don't already have homebrew installed, [install it here](http://brew.sh/).
|
69
|
-
|
70
70
|
# Usage
|
71
71
|
|
72
72
|
pem
|
data/lib/pem.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
-
require 'json'
|
2
1
|
require 'pem/version'
|
3
|
-
require 'pem/helper'
|
4
2
|
require 'pem/dependency_checker'
|
5
3
|
require 'pem/developer_center'
|
6
|
-
require 'pem/update_checker'
|
7
4
|
require 'pem/cert_manager'
|
8
5
|
require 'pem/signing_request'
|
9
6
|
|
10
|
-
|
11
|
-
require 'phantomjs/poltergeist'
|
12
|
-
require 'colored'
|
7
|
+
require 'fastlane_core'
|
13
8
|
|
14
9
|
module PEM
|
15
10
|
TMP_FOLDER = "/tmp/PEM/"
|
16
11
|
|
17
|
-
|
12
|
+
ENV['FASTLANE_TEAM_ID'] ||= ENV["PEM_TEAM_ID"]
|
13
|
+
|
14
|
+
Helper = FastlaneCore::Helper # you gotta love Ruby: Helper.* should use the Helper class contained in FastlaneCore
|
15
|
+
|
16
|
+
FastlaneCore::UpdateChecker.verify_latest_version('pem', PEM::VERSION)
|
18
17
|
DependencyChecker.check_dependencies
|
19
18
|
end
|
data/lib/pem/cert_manager.rb
CHANGED
@@ -7,7 +7,7 @@ module PEM
|
|
7
7
|
|
8
8
|
Helper.log.info "Refreshing push notification profiles for app '#{app_identifier}'"
|
9
9
|
|
10
|
-
dev =
|
10
|
+
dev = FastlaneCore::DeveloperCenter.new
|
11
11
|
|
12
12
|
cert_file = dev.fetch_cer_file(app_identifier, production)
|
13
13
|
rsa_file = File.join(TMP_FOLDER, 'private_key.key')
|
data/lib/pem/developer_center.rb
CHANGED
@@ -1,160 +1,10 @@
|
|
1
|
-
require '
|
2
|
-
require 'open-uri'
|
3
|
-
require 'openssl'
|
1
|
+
require 'fastlane_core/developer_center/developer_center'
|
4
2
|
|
5
|
-
|
6
|
-
require 'capybara/poltergeist'
|
7
|
-
require 'phantomjs/poltergeist'
|
8
|
-
|
9
|
-
module PEM
|
3
|
+
module FastlaneCore
|
10
4
|
class DeveloperCenter
|
11
|
-
# This error occurs only if there is something wrong with the given login data
|
12
|
-
class DeveloperCenterLoginError < StandardError
|
13
|
-
end
|
14
|
-
|
15
|
-
# This error can occur for many reaons. It is
|
16
|
-
# usually raised when a UI element could not be found
|
17
|
-
class DeveloperCenterGeneralError < StandardError
|
18
|
-
end
|
19
|
-
|
20
|
-
include Capybara::DSL
|
21
|
-
|
22
|
-
DEVELOPER_CENTER_URL = "https://developer.apple.com/devcenter/ios/index.action"
|
23
5
|
APP_IDS_URL = "https://developer.apple.com/account/ios/identifiers/bundle/bundleList.action"
|
24
6
|
|
25
|
-
|
26
|
-
PRODUCTION_SSL_CERTIFICATE_TITLE = "Production SSL Certificate"
|
27
|
-
DEVELOPMENT_SSL_CERTIFICATE_TITLE = "Development SSL Certificate"
|
28
|
-
|
29
|
-
def initialize
|
30
|
-
FileUtils.mkdir_p TMP_FOLDER
|
31
|
-
|
32
|
-
Capybara.run_server = false
|
33
|
-
Capybara.default_driver = :poltergeist
|
34
|
-
Capybara.javascript_driver = :poltergeist
|
35
|
-
Capybara.current_driver = :poltergeist
|
36
|
-
Capybara.app_host = DEVELOPER_CENTER_URL
|
37
|
-
|
38
|
-
# Since Apple has some SSL errors, we have to configure the client properly:
|
39
|
-
# https://github.com/ariya/phantomjs/issues/11239
|
40
|
-
Capybara.register_driver :poltergeist do |a|
|
41
|
-
conf = ['--debug=no', '--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1']
|
42
|
-
Capybara::Poltergeist::Driver.new(a, {
|
43
|
-
phantomjs: Phantomjs.path,
|
44
|
-
phantomjs_options: conf,
|
45
|
-
phantomjs_logger: File.open("#{TMP_FOLDER}/poltergeist_log.txt", "a"),
|
46
|
-
js_errors: false
|
47
|
-
})
|
48
|
-
end
|
49
|
-
|
50
|
-
page.driver.headers = { "Accept-Language" => "en" }
|
51
|
-
|
52
|
-
self.login
|
53
|
-
end
|
54
|
-
|
55
|
-
# Loggs in a user with the given login data on the Dev Center Frontend.
|
56
|
-
# You don't need to pass a username and password. It will
|
57
|
-
# Automatically be fetched using the {CredentialsManager::PasswordManager}.
|
58
|
-
# This method will also automatically be called when triggering other
|
59
|
-
# actions like {#open_app_page}
|
60
|
-
# @param user (String) (optional) The username/email address
|
61
|
-
# @param password (String) (optional) The password
|
62
|
-
# @return (bool) true if everything worked fine
|
63
|
-
# @raise [DeveloperCenterGeneralError] General error while executing
|
64
|
-
# this action
|
65
|
-
# @raise [DeveloperCenterLoginError] Login data is wrong
|
66
|
-
def login(user = nil, password = nil)
|
67
|
-
begin
|
68
|
-
Helper.log.info "Login into iOS Developer Center"
|
69
|
-
|
70
|
-
user ||= CredentialsManager::PasswordManager.shared_manager.username
|
71
|
-
password ||= CredentialsManager::PasswordManager.shared_manager.password
|
72
|
-
|
73
|
-
result = visit APP_IDS_URL
|
74
|
-
raise "Could not open Developer Center" unless result['status'] == 'success'
|
75
|
-
|
76
|
-
wait_for_elements(".button.blue").first.click
|
77
|
-
|
78
|
-
(wait_for_elements('#accountpassword') rescue nil) # when the user is already logged in, this will raise an exception
|
79
|
-
|
80
|
-
if page.has_content?"My Apps"
|
81
|
-
# Already logged in
|
82
|
-
return true
|
83
|
-
end
|
84
|
-
|
85
|
-
fill_in "accountname", with: user
|
86
|
-
fill_in "accountpassword", with: password
|
87
|
-
|
88
|
-
all(".button.large.blue.signin-button").first.click
|
89
|
-
|
90
|
-
begin
|
91
|
-
if page.has_content?"Select Team" # If the user is not on multiple teams
|
92
|
-
select_team
|
93
|
-
end
|
94
|
-
rescue => ex
|
95
|
-
Helper.log.debug ex
|
96
|
-
raise DeveloperCenterLoginError.new("Error loggin in user #{user}. User is on multiple teams and we were unable to correctly retrieve them.")
|
97
|
-
end
|
98
|
-
|
99
|
-
begin
|
100
|
-
visit APP_IDS_URL
|
101
|
-
wait_for_elements('.ios.bundles.gridList')
|
102
|
-
rescue => ex
|
103
|
-
Helper.log.debug ex
|
104
|
-
raise DeveloperCenterLoginError.new("Error logging in user #{user} with the given password. Make sure you entered them correctly.")
|
105
|
-
end
|
106
|
-
|
107
|
-
Helper.log.info "Login successful"
|
108
|
-
|
109
|
-
true
|
110
|
-
rescue => ex
|
111
|
-
error_occured(ex)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def select_team
|
116
|
-
team_id = ENV["PEM_TEAM_ID"]
|
117
|
-
team_id = nil if team_id.to_s.length == 0
|
118
|
-
|
119
|
-
unless team_id
|
120
|
-
Helper.log.info "You can store you preferred team using the environment variable `PEM_TEAM_ID`".green
|
121
|
-
Helper.log.info "Your ID belongs to the following teams:".green
|
122
|
-
end
|
123
|
-
|
124
|
-
available_options = []
|
125
|
-
|
126
|
-
teams = find("div.input").all('.team-value') # Grab all the teams data
|
127
|
-
teams.each_with_index do |val, index|
|
128
|
-
current_team_id = '"' + val.find("input").value + '"'
|
129
|
-
team_text = val.find(".label-primary").text
|
130
|
-
description_text = val.find(".label-secondary").text
|
131
|
-
description_text = "(#{description_text})" unless description_text.empty? # Include the team description if any
|
132
|
-
index_text = (index + 1).to_s + "."
|
133
|
-
|
134
|
-
available_options << [index_text, current_team_id, team_text, description_text].join(" ")
|
135
|
-
end
|
136
|
-
|
137
|
-
unless team_id
|
138
|
-
puts available_options.join("\n").green
|
139
|
-
team_index = ask("Please select the team number you would like to access: ".green)
|
140
|
-
team_id = teams[team_index.to_i - 1].find(".radio").value
|
141
|
-
end
|
142
|
-
|
143
|
-
team_button = first(:xpath, "//input[@type='radio' and @value='#{team_id}']") # Select the desired team
|
144
|
-
if team_button
|
145
|
-
team_button.click
|
146
|
-
else
|
147
|
-
Helper.log.fatal "Could not find given Team. Available options: ".red
|
148
|
-
puts available_options.join("\n").yellow
|
149
|
-
raise DeveloperCenterLoginError.new("Error finding given team #{team_id}.".red)
|
150
|
-
end
|
151
|
-
|
152
|
-
all(".button.large.blue.submit").first.click
|
153
|
-
|
154
|
-
result = visit APP_IDS_URL
|
155
|
-
raise "Could not open Developer Center" unless result['status'] == 'success'
|
156
|
-
end
|
157
|
-
|
7
|
+
|
158
8
|
# This method will enable push for the given app
|
159
9
|
# and download the cer file in any case, no matter if it existed before or not
|
160
10
|
# @return the path to the push file
|
@@ -187,6 +37,10 @@ module PEM
|
|
187
37
|
visit APP_IDS_URL
|
188
38
|
sleep 5
|
189
39
|
|
40
|
+
wait_for_elements(".toolbar-button.search").first.click
|
41
|
+
fill_in "bundle-list-search", with: app_identifier
|
42
|
+
sleep 5
|
43
|
+
|
190
44
|
apps = all(:xpath, "//td[@title='#{app_identifier}']")
|
191
45
|
if apps.count == 1
|
192
46
|
apps.first.click
|
@@ -258,43 +112,12 @@ module PEM
|
|
258
112
|
raise "Can't write to #{TMP_FOLDER}"
|
259
113
|
end
|
260
114
|
|
261
|
-
Helper.log.info "Successfully downloaded latest .cer file.
|
115
|
+
Helper.log.info "Successfully downloaded latest .cer file to '#{path}'".green
|
262
116
|
return path
|
263
117
|
end
|
264
118
|
|
265
|
-
|
266
|
-
private
|
267
119
|
def click_next
|
268
120
|
wait_for_elements('.button.small.blue.right.submit').last.click
|
269
121
|
end
|
270
|
-
|
271
|
-
def error_occured(ex)
|
272
|
-
snap
|
273
|
-
raise ex # re-raise the error after saving the snapshot
|
274
|
-
end
|
275
|
-
|
276
|
-
def snap
|
277
|
-
path = "Error#{Time.now.to_i}.png"
|
278
|
-
save_screenshot(path, :full => true)
|
279
|
-
system("open '#{path}'")
|
280
|
-
end
|
281
|
-
|
282
|
-
def wait_for_elements(name)
|
283
|
-
counter = 0
|
284
|
-
results = all(name)
|
285
|
-
while results.count == 0
|
286
|
-
# Helper.log.debug "Waiting for #{name}"
|
287
|
-
sleep 0.2
|
288
|
-
|
289
|
-
results = all(name)
|
290
|
-
|
291
|
-
counter += 1
|
292
|
-
if counter > 100
|
293
|
-
Helper.log.debug caller
|
294
|
-
raise DeveloperCenterGeneralError.new("Couldn't find element '#{name}' after waiting for quite some time")
|
295
|
-
end
|
296
|
-
end
|
297
|
-
return results
|
298
|
-
end
|
299
122
|
end
|
300
123
|
end
|
data/lib/pem/version.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
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-02-
|
11
|
+
date: 2015-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: fastlane_core
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - '>='
|
@@ -24,104 +24,6 @@ dependencies:
|
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: highline
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ~>
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.6.21
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ~>
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 1.6.21
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: colored
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - '>='
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - '>='
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: commander
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ~>
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 4.2.0
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 4.2.0
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: credentials_manager
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - '>='
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :runtime
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - '>='
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: phantomjs
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ~>
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: 1.9.8
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ~>
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 1.9.8
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: capybara
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ~>
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: 2.4.3
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ~>
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: 2.4.3
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: poltergeist
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ~>
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: 1.5.1
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ~>
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: 1.5.1
|
125
27
|
- !ruby/object:Gem::Dependency
|
126
28
|
name: bundler
|
127
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -235,9 +137,7 @@ files:
|
|
235
137
|
- lib/pem/cert_manager.rb
|
236
138
|
- lib/pem/dependency_checker.rb
|
237
139
|
- lib/pem/developer_center.rb
|
238
|
-
- lib/pem/helper.rb
|
239
140
|
- lib/pem/signing_request.rb
|
240
|
-
- lib/pem/update_checker.rb
|
241
141
|
- lib/pem/version.rb
|
242
142
|
homepage: http://fastlane.tools
|
243
143
|
licenses:
|
data/lib/pem/helper.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'logger'
|
2
|
-
|
3
|
-
module PEM
|
4
|
-
module Helper
|
5
|
-
|
6
|
-
# Logging happens using this method
|
7
|
-
def self.log
|
8
|
-
if is_test?
|
9
|
-
@@log ||= Logger.new(nil) # don't show any logs when running tests
|
10
|
-
else
|
11
|
-
@@log ||= Logger.new(STDOUT)
|
12
|
-
end
|
13
|
-
|
14
|
-
@@log.formatter = proc do |severity, datetime, progname, msg|
|
15
|
-
string = "#{severity} [#{datetime.strftime('%Y-%m-%d %H:%M:%S.%2N')}]: "
|
16
|
-
second = "#{msg}\n"
|
17
|
-
|
18
|
-
if severity == "DEBUG"
|
19
|
-
string = string.magenta
|
20
|
-
elsif severity == "INFO"
|
21
|
-
string = string.white
|
22
|
-
elsif severity == "WARN"
|
23
|
-
string = string.yellow
|
24
|
-
elsif severity == "ERROR"
|
25
|
-
string = string.red
|
26
|
-
elsif severity == "FATAL"
|
27
|
-
string = string.red.bold
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
[string, second].join("")
|
32
|
-
end
|
33
|
-
|
34
|
-
@@log
|
35
|
-
end
|
36
|
-
|
37
|
-
# @return true if the currently running program is a unit test
|
38
|
-
def self.is_test?
|
39
|
-
defined?SpecHelper
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return the full path to the Xcode developer tools of the currently
|
43
|
-
# running system
|
44
|
-
def self.xcode_path
|
45
|
-
return "" if self.is_test? and not OS.mac?
|
46
|
-
`xcode-select -p`.gsub("\n", '') + "/"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/lib/pem/update_checker.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
|
3
|
-
module PEM
|
4
|
-
# Verifies, the user runs the latest version of this gem
|
5
|
-
class UpdateChecker
|
6
|
-
# This method will check if the latest version is installed and show a warning if that's not the case
|
7
|
-
def self.verify_latest_version
|
8
|
-
if self.update_available?
|
9
|
-
v = fetch_latest
|
10
|
-
puts '#######################################################################'.green
|
11
|
-
puts "# PEM #{v} is available.".green
|
12
|
-
puts "# It is recommended to use the latest version.".green
|
13
|
-
puts "# Update using '(sudo) gem update PEM'.".green
|
14
|
-
puts "# To see what's new, open https://github.com/KrauseFx/PEM/releases.".green
|
15
|
-
puts '#######################################################################'.green
|
16
|
-
return true
|
17
|
-
end
|
18
|
-
false
|
19
|
-
end
|
20
|
-
|
21
|
-
# Is a new official release available (this does not include pre-releases)
|
22
|
-
def self.update_available?
|
23
|
-
begin
|
24
|
-
latest = fetch_latest
|
25
|
-
if latest and Gem::Version.new(latest) > Gem::Version.new(current_version)
|
26
|
-
return true
|
27
|
-
end
|
28
|
-
rescue => ex
|
29
|
-
Helper.log.error("Could not check if 'PEM' is up to date.")
|
30
|
-
end
|
31
|
-
return false
|
32
|
-
end
|
33
|
-
|
34
|
-
# The currently used version of this gem
|
35
|
-
def self.current_version
|
36
|
-
PEM::VERSION
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
def self.fetch_latest
|
41
|
-
JSON.parse(open("http://rubygems.org/api/v1/gems/pem.json").read)["version"]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|