apprepo 0.0.6 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -9
- data/lib/apprepo.rb +12 -25
- data/lib/apprepo/analyser.rb +26 -0
- data/lib/apprepo/commands_generator.rb +50 -39
- data/lib/apprepo/detect_values.rb +8 -20
- data/lib/apprepo/loader.rb +4 -2
- data/lib/apprepo/manifest.rb +9 -2
- data/lib/apprepo/options.rb +34 -14
- data/lib/apprepo/runner.rb +20 -19
- data/lib/apprepo/setup.rb +8 -9
- data/lib/apprepo/uploader.rb +208 -124
- data/lib/apprepo/version.rb +3 -3
- metadata +5 -28
- data/lib/apprepo/download_metadata.rb +0 -44
- data/lib/apprepo/upload_assets.rb +0 -22
- data/lib/apprepo/upload_descriptor.rb +0 -12
- data/lib/apprepo/upload_metadata.rb +0 -192
data/lib/apprepo/runner.rb
CHANGED
@@ -1,64 +1,65 @@
|
|
1
1
|
require_relative 'uploader'
|
2
2
|
|
3
3
|
module AppRepo
|
4
|
+
# Responsible for running
|
4
5
|
class Runner
|
5
6
|
attr_accessor :options
|
6
7
|
|
7
8
|
def initialize(options)
|
8
|
-
UI.message('[AppRepo:Runner] Initializing...')
|
9
9
|
self.options = options
|
10
10
|
AppRepo::DetectValues.new.run!(self.options)
|
11
|
-
# FastlaneCore::PrintTable.print_values(config: options,
|
11
|
+
# FastlaneCore::PrintTable.print_values(config: options,
|
12
|
+
# hide_keys: [:app], mask_keys: [],
|
13
|
+
# title: "deliver #{AppRepo::VERSION} Summary")
|
12
14
|
end
|
13
15
|
|
16
|
+
# rubocop:disable Metrics/AbcSize
|
17
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
14
18
|
def run
|
15
|
-
UI.success('
|
16
|
-
verify_version
|
19
|
+
UI.success('AppRepo SFTP Uploader running...')
|
20
|
+
verify_version unless options[:app_version].to_s.empty?
|
17
21
|
upload_metadata
|
18
|
-
|
19
|
-
has_binary = (options[:ipa] || options[:pkg])
|
22
|
+
has_binary = options[:ipa]
|
20
23
|
if !options[:skip_binary_upload] && !options[:build_number] && has_binary
|
21
24
|
upload_binary
|
22
25
|
end
|
23
|
-
|
24
26
|
UI.success('Finished the upload to AppRepo.')
|
25
|
-
|
26
|
-
notify if options[:notify]
|
27
|
+
notify unless options[:notify].nil?
|
27
28
|
end
|
28
29
|
|
29
30
|
# Make sure the version on AppRepo matches the one in the ipa
|
30
31
|
# If not, the new version will automatically be created
|
31
32
|
def verify_version
|
32
33
|
app_version = options[:app_version]
|
33
|
-
|
34
|
+
msg = "TODO: Test if AppRepo matches '#{app_version}' from the IPA..."
|
35
|
+
UI.message(msg)
|
34
36
|
|
35
37
|
# changed = options[:app].ensure_version!(app_version)
|
36
38
|
# if changed
|
37
39
|
# UI.success("Successfully set the version to '#{app_version}'")
|
38
40
|
# else
|
39
|
-
# UI.success("'#{app_version}' is the latest version on
|
41
|
+
# UI.success("'#{app_version}' is the latest version on AppRepo")
|
40
42
|
# end
|
41
43
|
end
|
42
44
|
|
43
|
-
# Upload all metadata, screenshots, pricing information, etc. to
|
45
|
+
# Upload all metadata, screenshots, pricing information, etc. to AppRepo
|
44
46
|
def upload_metadata
|
45
47
|
#
|
46
48
|
end
|
47
49
|
|
48
|
-
# Upload the binary to
|
50
|
+
# Upload the binary to AppRepo
|
49
51
|
def upload_binary
|
50
|
-
UI.message('Uploading binary to AppRepo')
|
51
52
|
if options[:ipa]
|
52
|
-
AppRepo::Uploader.new(options)
|
53
|
-
|
54
|
-
|
53
|
+
uploader = AppRepo::Uploader.new(options)
|
54
|
+
result = uploader.upload
|
55
|
+
msg = 'Binary upload failed. Check out the error above'
|
56
|
+
UI.user_error!(msg) unless result
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
60
|
def notify
|
59
61
|
# should be in metadata
|
62
|
+
UI.message('TODO: Missing implementation for AppRepo Push Notifier')
|
60
63
|
end
|
61
|
-
|
62
|
-
private
|
63
64
|
end
|
64
65
|
end
|
data/lib/apprepo/setup.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
module AppRepo
|
2
|
+
# Responsible for setting up the Repofile configuration
|
2
3
|
class Setup
|
3
4
|
def setup_apprepo(file_path, data, _apprepo_path, _options)
|
4
5
|
UI.message('[AppRepo:Setup] Setting up...')
|
5
6
|
File.write(file_path, data)
|
6
7
|
|
7
8
|
# TODO: implement later
|
8
|
-
|
9
|
+
download_manifest(apprepo_path, options)
|
9
10
|
|
10
11
|
UI.success("NOT! created new Repofile at path '#{file_path}'")
|
11
12
|
end
|
12
13
|
|
13
|
-
# This method takes care of creating a new 'apprepo' folder
|
14
|
+
# This method takes care of creating a new 'apprepo' folder with metadata
|
14
15
|
# and screenshots folders
|
15
16
|
def generate_apprepo_file(_apprepo_path, options)
|
16
|
-
#
|
17
17
|
# v = options[:app].latest_version
|
18
|
-
#
|
18
|
+
# generate_apprepo_file(v, File.join(apprepo_path, 'manifest.json'))
|
19
19
|
|
20
20
|
# Generate the final Repofile here
|
21
21
|
gem_path = Helper.gem_path('apprepo')
|
@@ -24,15 +24,14 @@ module AppRepo
|
|
24
24
|
apprepo.gsub!('[[APPREPO_IPA_PATH]]', options[:app].file_path)
|
25
25
|
apprepo.gsub!('[[APP_VERSION]]', options[:app].version)
|
26
26
|
apprepo.gsub!('[[APP_NAME]]', options[:app].name)
|
27
|
-
|
28
|
-
# deliver => apprepo??
|
27
|
+
# apprepo (was deliver)
|
29
28
|
end
|
30
29
|
|
31
|
-
def
|
30
|
+
def download_manifest(apprepo_path, _options)
|
32
31
|
path = File.join(apprepo_path, 'metadata')
|
33
32
|
FileUtils.mkdir_p(path)
|
34
|
-
UI.success("TODO: DOWNLOAD
|
35
|
-
|
33
|
+
UI.success("TODO: DOWNLOAD MANIFEST'")
|
34
|
+
AppRepo::Uploader.download_metadata(options, path)
|
36
35
|
end
|
37
36
|
|
38
37
|
def run(options)
|
data/lib/apprepo/uploader.rb
CHANGED
@@ -10,9 +10,11 @@ require 'fastlane_core'
|
|
10
10
|
require 'fastlane_core/languages'
|
11
11
|
|
12
12
|
require_relative 'options'
|
13
|
-
require_relative 'upload_descriptor' # will deprecate, should have contain Repofile data but it will be in options as expected
|
14
13
|
|
15
14
|
module AppRepo
|
15
|
+
# rubocop:disable Metrics/ClassLength
|
16
|
+
|
17
|
+
# Responsible for performing the SFTP operation
|
16
18
|
class Uploader
|
17
19
|
attr_accessor :options
|
18
20
|
|
@@ -28,176 +30,258 @@ module AppRepo
|
|
28
30
|
attr_accessor :manifest_path
|
29
31
|
attr_accessor :appcode
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
self.
|
35
|
-
self.
|
36
|
-
self.
|
37
|
-
self.
|
38
|
-
self.
|
39
|
-
self.
|
40
|
-
|
33
|
+
# rubocop:disable Metrics/AbcSize
|
34
|
+
# rubocop:disable Metrics/MethodLength
|
35
|
+
def initialize(options)
|
36
|
+
self.options = options unless options.nil?
|
37
|
+
self.host = options[:repo_url] # 'repo.teacloud.net'
|
38
|
+
self.user = options[:repo_user]
|
39
|
+
self.password = options[:repo_password]
|
40
|
+
self.rsa_keypath = options[:repo_key] # '../assets/circle.key'
|
41
|
+
self.ipa_path = options[:ipa] # '../sampleapp.ipa'
|
42
|
+
self.manifest_path = options[:manifest_path] # '../assets/example_manifest.json'
|
43
|
+
self.appcode = options[:appcode]
|
44
|
+
|
41
45
|
# AppRepo::Uploader.new.run!
|
42
|
-
# FastlaneCore::PrintTable.print_values(config: nil , hide_keys: [:app],
|
46
|
+
# FastlaneCore::PrintTable.print_values(config: nil , hide_keys: [:app],
|
47
|
+
# mask_keys: ['app_review_information.demo_password'],
|
48
|
+
# title: "deliver #{AppRepo::VERSION} Summary") # options
|
43
49
|
end
|
44
50
|
|
45
51
|
#
|
46
|
-
#
|
52
|
+
# Upload IPA & manifest
|
47
53
|
#
|
48
54
|
|
49
|
-
|
55
|
+
# rubocop:disable Metrics/AbcSize
|
56
|
+
# rubocop:disable Metrics/MethodLength
|
57
|
+
def upload
|
50
58
|
# Login & Upload IPA with metadata using RSA key or username/password
|
51
|
-
rsa_key = load_rsa_key(
|
59
|
+
rsa_key = load_rsa_key(rsa_keypath)
|
60
|
+
success = false
|
61
|
+
if !rsa_key.nil?
|
62
|
+
FastlaneCore::UI.message('Logging in with RSA key...')
|
63
|
+
Net::SSH.start(host, user, key_data: rsa_key, keys_only: true) do |ssh|
|
64
|
+
FastlaneCore::UI.message('Uploading IPA & Manifest...')
|
65
|
+
success = ssh_sftp_upload(ssh, ipa_path, manifest_path)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
FastlaneCore::UI.message('Logging in...')
|
69
|
+
Net::SSH.start(host, user, password: password) do |ssh|
|
70
|
+
self.ssh_session = ssh
|
71
|
+
FastlaneCore::UI.message('Logged in, uploading IPA & Manifest...')
|
72
|
+
success = ssh_sftp_upload(ssh, ipa_path, manifest_path)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
success
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Download metadata only
|
80
|
+
#
|
81
|
+
|
82
|
+
# rubocop:disable Metrics/AbcSize
|
83
|
+
# rubocop:disable Metrics/MethodLength
|
84
|
+
def download_metadata
|
85
|
+
rsa_key = load_rsa_key(rsa_keypath)
|
52
86
|
if rsa_key?
|
53
|
-
|
54
|
-
Fastlane::UI.message('[AppRepo:Uploader] Logging in with RSA key ' + rsa_keypath)
|
87
|
+
FastlaneCore::UI.message('Logging in with RSA key...')
|
55
88
|
Net::SSH.start(host, user, key_data: rsa_key, keys_only: true) do |ssh|
|
56
|
-
|
57
|
-
|
89
|
+
self.ssh_session = ssh
|
90
|
+
FastlaneCore::UI.message('Uploading UPA & Manifest...')
|
91
|
+
ssh_sftp_download(ssh, manifest_path)
|
58
92
|
end
|
59
93
|
else
|
60
|
-
|
61
|
-
Fastlane::UI.message('[AppRepo:Uploader] Logging in with username ' + user + ' and password *****...')
|
94
|
+
FastlaneCore::UI.message('Logging in...')
|
62
95
|
Net::SSH.start(host, user, password: password) do |ssh|
|
63
|
-
|
64
|
-
|
96
|
+
self.ssh_session = ssh
|
97
|
+
FastlaneCore::UI.message('Logged in, uploading UPA & Manifest...')
|
98
|
+
ssh_sftp_download(ssh, manifest_path)
|
65
99
|
end
|
66
100
|
end
|
67
101
|
end
|
68
102
|
|
103
|
+
private
|
104
|
+
|
105
|
+
def ssh_sftp_download(ssh, local_ipa_path, _manifest_path)
|
106
|
+
ssh.sftp.connect do |sftp|
|
107
|
+
break unless check_ipa(local_ipa_path)
|
108
|
+
FastlaneCore::UI.message('[Downloading] Will start...')
|
109
|
+
manifest = download_manifest(sftp)
|
110
|
+
puts '********************************************************'
|
111
|
+
puts JSON.pretty_generate(manifest)
|
112
|
+
puts '********************************************************'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
69
116
|
def ssh_sftp_upload(ssh, local_ipa_path, manifest_path)
|
70
117
|
ssh.sftp.connect do |sftp|
|
118
|
+
break unless check_ipa(local_ipa_path)
|
119
|
+
check_appcode(sftp, appcode)
|
120
|
+
path = remote_path(appcode)
|
121
|
+
manifest = download_manifest(sftp)
|
122
|
+
puts JSON.pretty_generate(manifest) unless manifest.nil?
|
123
|
+
bump_ipa(sftp, local_ipa_path, appcode)
|
124
|
+
remote_ipa_path = get_remote_ipa_path(local_ipa_path, appcode)
|
125
|
+
upload_ipa(sftp, local_ipa_path, remote_ipa_path)
|
126
|
+
upload_manifest(sftp, manifest_path, remote_manifest_path(appcode))
|
127
|
+
# Lists the entries in a directory for verification
|
128
|
+
sftp.dir.foreach(path) do |entry|
|
129
|
+
FastlaneCore::UI.message(entry.longname)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
71
133
|
|
72
|
-
|
134
|
+
# Check IPA existence locally
|
135
|
+
#
|
136
|
+
# @param local_ipa_path
|
137
|
+
def check_ipa(local_ipa_path)
|
138
|
+
if File.exist?(local_ipa_path)
|
139
|
+
FastlaneCore::UI.important('IPA found at ' + local_ipa_path)
|
140
|
+
return true
|
141
|
+
else
|
142
|
+
FastlaneCore::UI.verbose('IPA at given path does not exist yet.')
|
143
|
+
return false
|
144
|
+
end
|
145
|
+
end
|
73
146
|
|
74
|
-
|
75
|
-
Fastlane::UI.message('[AppRepo:Uploader] Local IPA found at ' + local_ipa_path)
|
76
|
-
else
|
77
|
-
Fastlane::UI.message('[AppRepo:Uploader] IPA at given path does not exist!')
|
78
|
-
return
|
79
|
-
end
|
147
|
+
# Private methods - Remote Operations
|
80
148
|
|
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
|
-
puts json
|
110
|
-
puts '****************************************************************'
|
149
|
+
# Checks/creates remote APPCODE directory
|
150
|
+
# @param sftp
|
151
|
+
# @param [String] appcode
|
152
|
+
def check_appcode(sftp, appcode)
|
153
|
+
path = remote_path(appcode)
|
154
|
+
FastlaneCore::UI.message('Checking APPCODE')
|
155
|
+
remote_mkdir(sftp, path)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Checks/renames remote IPA
|
159
|
+
#
|
160
|
+
# @params sftp
|
161
|
+
# @params [String] local_ipa_path
|
162
|
+
def bump_ipa(sftp, local, appcode)
|
163
|
+
remote = get_remote_ipa_path(local, appcode)
|
164
|
+
FastlaneCore::UI.message('Checking remote IPA')
|
165
|
+
begin
|
166
|
+
sftp.stat!(remote) do |response|
|
167
|
+
if response.ok?
|
168
|
+
begin
|
169
|
+
sftp.rename!(remote, remote + '.bak')
|
170
|
+
rescue
|
171
|
+
begin
|
172
|
+
sftp.remove(remote + '.bak') # may fail if not existent
|
173
|
+
FastlaneCore::UI.message('Removed ' + remote + '.bak')
|
174
|
+
rescue
|
175
|
+
sftp.rename!(remote, remote + '.bak')
|
176
|
+
FastlaneCore::UI.message('Bumped to ' + remote + '.bak')
|
111
177
|
end
|
112
178
|
end
|
113
179
|
end
|
114
|
-
rescue
|
115
|
-
Fastlane::UI.message('[AppRepo:Uploader] No previous Manifest found.')
|
116
180
|
end
|
181
|
+
rescue
|
182
|
+
FastlaneCore::UI.message('No previous IPA found.')
|
183
|
+
end
|
184
|
+
end
|
117
185
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
186
|
+
# Downloads remote manifest, self.appcode required by options.
|
187
|
+
#
|
188
|
+
# @param sftp
|
189
|
+
# @param [String] remote_path
|
190
|
+
# @returns [JSON] json or nil
|
191
|
+
def download_manifest(sftp)
|
192
|
+
FastlaneCore::UI.message('Checking remote Manifest')
|
193
|
+
json = nil
|
194
|
+
remote_manifest_path = remote_manifest_path(appcode)
|
195
|
+
begin
|
196
|
+
sftp.stat!(remote_manifest_path) do |response|
|
197
|
+
if response.ok?
|
198
|
+
FastlaneCore::UI.success('Loading remote manifest:')
|
199
|
+
manifest = sftp.download!(remote_manifest_path)
|
200
|
+
json = JSON.parse(manifest)
|
132
201
|
end
|
133
|
-
rescue
|
134
|
-
Fastlane::UI.message('[AppRepo:Uploader] No previous IPA found.')
|
135
202
|
end
|
203
|
+
rescue
|
204
|
+
FastlaneCore::UI.message('No previous Manifest found')
|
205
|
+
end
|
206
|
+
json
|
207
|
+
end
|
136
208
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
# Lists the entries in a directory for verification
|
160
|
-
#
|
209
|
+
# Upload current IPA
|
210
|
+
#
|
211
|
+
# @param sftp
|
212
|
+
# @param [String] local_ipa_path
|
213
|
+
# @param [String] remote_ipa_path
|
214
|
+
def upload_ipa(sftp, local_ipa_path, remote_ipa_path)
|
215
|
+
msg = '[Uploading IPA] ' + local_ipa_path + ' to ' + remote_ipa_path
|
216
|
+
FastlaneCore::UI.message(msg)
|
217
|
+
result = sftp.upload!(local_ipa_path, remote_ipa_path) do |event, _uploader, *_args|
|
218
|
+
case event
|
219
|
+
when :open then
|
220
|
+
putc '.'
|
221
|
+
when :put then
|
222
|
+
putc '.'
|
223
|
+
$stdout.flush
|
224
|
+
when :close then
|
225
|
+
puts "\n"
|
226
|
+
when :finish then
|
227
|
+
FastlaneCore::UI.success('Upload successful!')
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
161
231
|
|
162
|
-
|
163
|
-
|
232
|
+
# Upload current manifest.json
|
233
|
+
#
|
234
|
+
# @param sftp
|
235
|
+
# @param [String] manifest_path
|
236
|
+
# @param [String] remote_manifest_path
|
237
|
+
def upload_manifest(sftp, local_path, remote_path)
|
238
|
+
msg = '[Uploading Manifest] ' + local_path + ' to ' + remote_path
|
239
|
+
FastlaneCore::UI.message(msg)
|
240
|
+
result = sftp.upload!(local_path, remote_path) do |event, _uploader, *_args|
|
241
|
+
case event
|
242
|
+
when :finish then
|
243
|
+
FastlaneCore::UI.success('Upload successful!')
|
164
244
|
end
|
165
245
|
end
|
166
246
|
end
|
167
247
|
|
168
|
-
|
248
|
+
def get_remote_ipa_path(local_ipa_path, appcode)
|
249
|
+
remote_path(appcode) + File.basename(local_ipa_path)
|
250
|
+
end
|
251
|
+
|
252
|
+
def remote_path(appcode)
|
253
|
+
generate_remote_path + appcode + '/'
|
254
|
+
end
|
169
255
|
|
170
|
-
def
|
171
|
-
|
172
|
-
Fastlane::UI.message('[AppRepo:Uploader] remote_ipa_path: ' + path)
|
173
|
-
path
|
256
|
+
def remote_manifest_path(appcode)
|
257
|
+
remote_manifest_path = remote_path(appcode) + 'manifest.json'
|
174
258
|
end
|
175
259
|
|
176
|
-
def
|
177
|
-
|
178
|
-
Fastlane::UI.message('[AppRepo:Uploader] get_remote_path: ' + path)
|
179
|
-
path
|
260
|
+
def generate_remote_path
|
261
|
+
'/home/' + user + '/repo/apps/'
|
180
262
|
end
|
181
263
|
|
182
|
-
|
264
|
+
def remote_mkdir(sftp, remote_path)
|
183
265
|
sftp.mkdir remote_path
|
184
266
|
rescue Net::SFTP::StatusException => e
|
185
|
-
if e.code
|
186
|
-
|
187
|
-
|
188
|
-
raise
|
189
|
-
end
|
267
|
+
raise if e.code != 11
|
268
|
+
msg = 'Remote dir ' + remote_path + ' exists.'
|
269
|
+
FastlaneCore::UI.message(msg)
|
190
270
|
end
|
191
271
|
|
192
|
-
# Private methods
|
272
|
+
# Private methods - Local Operations
|
193
273
|
|
194
274
|
def load_rsa_key(rsa_keypath)
|
195
|
-
File.open(
|
275
|
+
File.open(rsa_keypath, 'r') do |file|
|
276
|
+
rsa_key = nil
|
196
277
|
rsa_key = [file.read]
|
197
|
-
|
198
|
-
|
278
|
+
if !rsa_key.nil?
|
279
|
+
FastlaneCore::UI.success('Successfully loaded RSA key...')
|
280
|
+
else
|
281
|
+
FastlaneCore::UI.user_error!('Failed to load RSA key...')
|
282
|
+
end
|
283
|
+
rsa_key
|
199
284
|
end
|
200
285
|
end
|
201
|
-
|
202
286
|
end
|
203
287
|
end
|