fastlane-plugin-appcenter 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cfaf06714cd6c125dd4fb5b199e9d519fcf3fbaa
4
- data.tar.gz: 0dd75092e7436bdf0e10276f2c1bc6924ad39b3b
2
+ SHA256:
3
+ metadata.gz: b7aee7355c0b29ee7bf79054cf8a1036b59ccf37adb847b9dc0dc62cf421f25f
4
+ data.tar.gz: bb7c314a2e16662fd9aef3d820fb6e31e097f7ccff7807ab2d4e990b8c0d8e72
5
5
  SHA512:
6
- metadata.gz: bf78aae4984955537de575c92b0ca2d524f7d15372b92aceb67ea95f4e1c02ce38fc74c1a26309bfbf773354de1d34f7d706efbc01787e28cf5a4a2e06bcb68f
7
- data.tar.gz: 541f2b17ce6d55cb681b26d7b5d6915c9c7fe7ae8374acb2c9b5ad288e5524b8b182b5528bdcac1646ddfd59a27b746b45031b7f2268121baad3d56db52d5bdc
6
+ metadata.gz: 2c24839b70a4b7366b8966a57adabf13b66e6f04e94c494f1f851d49e7ca0620cbca701c217af7990abf1f1591b16ca46950c37a0ad2ad4072c4b34d195e7e4c
7
+ data.tar.gz: 5667213b8132cc43957cd3dc5124b579104e5c3cac9eaeeb012440a3c54bfe13b3618a38646edc31f7b99debe0a2b5f2b748fa649eb2e890d3dec9866f548f5d
data/README.md CHANGED
@@ -38,7 +38,11 @@ The action parameters `api_token` and `owner_name` can also be omitted when thei
38
38
  - `APPCENTER_DISTRIBUTE_DSYM` - Path to your symbols file. For iOS provide path to app.dSYM.zip
39
39
  - `APPCENTER_DISTRIBUTE_UPLOAD_DSYM_ONLY` - Flag to upload only the dSYM file to App Center
40
40
  - `APPCENTER_DISTRIBUTE_GROUP` - Comma separated list of Distribution Group names
41
+ - `APPCENTER_DISTRIBUTE_MANDATORY_UPDATE` - Require users to update to this release
42
+ - `APPCENTER_DISTRIBUTE_NOTIFY_TESTERS` - Send email notification about release
41
43
  - `APPCENTER_DISTRIBUTE_RELEASE_NOTES` - Release notes
44
+ - `APPCENTER_DISTRIBUTE_RELEASE_NOTES_CLIPPING` - Clip release notes if its length is more then 5000, `true` by default
45
+ - `APPCENTER_DISTRIBUTE_RELEASE_NOTES_LINK` - Additional release notes link
42
46
 
43
47
  ## Example
44
48
 
@@ -1,262 +1,10 @@
1
- # rubocop:disable Metrics/ClassLength
2
1
  module Fastlane
3
2
  module Actions
4
- module SharedValues
5
- APPCENTER_DOWNLOAD_LINK = :APPCENTER_DOWNLOAD_LINK
6
- APPCENTER_BUILD_INFORMATION = :APPCENTER_BUILD_INFORMATION
7
- end
8
-
9
3
  module Constants
10
4
  MAX_RELEASE_NOTES_LENGTH = 5000
11
5
  end
12
6
 
13
7
  class AppcenterUploadAction < Action
14
- # create request
15
- def self.connection(upload_url = false, dsym = false)
16
- require 'faraday'
17
- require 'faraday_middleware'
18
-
19
- options = {
20
- url: upload_url ? upload_url : "https://api.appcenter.ms"
21
- }
22
-
23
- Faraday.new(options) do |builder|
24
- if upload_url
25
- builder.request :multipart unless dsym
26
- builder.request :url_encoded unless dsym
27
- else
28
- builder.request :json
29
- end
30
- builder.response :json, content_type: /\bjson$/
31
- builder.use FaradayMiddleware::FollowRedirects
32
- builder.adapter :net_http
33
- end
34
- end
35
-
36
- # creates new release upload
37
- # returns:
38
- # upload_id
39
- # upload_url
40
- def self.create_release_upload(api_token, owner_name, app_name)
41
- connection = self.connection
42
-
43
- response = connection.post do |req|
44
- req.url("/v0.1/apps/#{owner_name}/#{app_name}/release_uploads")
45
- req.headers['X-API-Token'] = api_token
46
- req.headers['internal-request-source'] = "fastlane"
47
- req.body = {}
48
- end
49
-
50
- case response.status
51
- when 200...300
52
- UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
53
- response.body
54
- when 401
55
- UI.user_error!("Auth Error, provided invalid token")
56
- false
57
- when 404
58
- UI.error("Not found, invalid owner or application name")
59
- false
60
- else
61
- UI.error("Error #{response.status}: #{response.body}")
62
- false
63
- end
64
- end
65
-
66
- # creates new dSYM upload in appcenter
67
- # returns:
68
- # symbol_upload_id
69
- # upload_url
70
- # expiration_date
71
- def self.create_dsym_upload(api_token, owner_name, app_name)
72
- connection = self.connection
73
-
74
- response = connection.post do |req|
75
- req.url("/v0.1/apps/#{owner_name}/#{app_name}/symbol_uploads")
76
- req.headers['X-API-Token'] = api_token
77
- req.headers['internal-request-source'] = "fastlane"
78
- req.body = {
79
- symbol_type: 'Apple'
80
- }
81
- end
82
-
83
- case response.status
84
- when 200...300
85
- UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
86
- response.body
87
- when 401
88
- UI.user_error!("Auth Error, provided invalid token")
89
- false
90
- when 404
91
- UI.error("Not found, invalid owner or application name")
92
- false
93
- else
94
- UI.error("Error #{response.status}: #{response.body}")
95
- false
96
- end
97
- end
98
-
99
- # committs or aborts dsym upload
100
- def self.update_dsym_upload(api_token, owner_name, app_name, symbol_upload_id, status)
101
- connection = self.connection
102
-
103
- response = connection.patch do |req|
104
- req.url("/v0.1/apps/#{owner_name}/#{app_name}/symbol_uploads/#{symbol_upload_id}")
105
- req.headers['X-API-Token'] = api_token
106
- req.headers['internal-request-source'] = "fastlane"
107
- req.body = {
108
- "status" => status
109
- }
110
- end
111
-
112
- case response.status
113
- when 200...300
114
- UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
115
- response.body
116
- else
117
- UI.error("Error #{response.status}: #{response.body}")
118
- false
119
- end
120
- end
121
-
122
- # upload dSYM files to specified upload url
123
- # if succeed, then commits the upload
124
- # otherwise aborts
125
- def self.upload_dsym(api_token, owner_name, app_name, dsym, symbol_upload_id, upload_url)
126
- connection = self.connection(upload_url, true)
127
-
128
- response = connection.put do |req|
129
- req.headers['x-ms-blob-type'] = "BlockBlob"
130
- req.headers['Content-Length'] = File.size(dsym).to_s
131
- req.headers['internal-request-source'] = "fastlane"
132
- req.body = Faraday::UploadIO.new(dsym, 'application/octet-stream') if dsym && File.exist?(dsym)
133
- end
134
-
135
- case response.status
136
- when 200...300
137
- self.update_dsym_upload(api_token, owner_name, app_name, symbol_upload_id, 'committed')
138
- UI.success("dSYM uploaded")
139
- else
140
- UI.error("Error uploading dSYM #{response.status}: #{response.body}")
141
- self.update_dsym_upload(api_token, owner_name, app_name, symbol_upload_id, 'aborted')
142
- UI.error("dSYM upload aborted")
143
- false
144
- end
145
- end
146
-
147
- # upload binary for specified upload_url
148
- # if succeed, then commits the release
149
- # otherwise aborts
150
- def self.upload_build(api_token, owner_name, app_name, file, upload_id, upload_url)
151
- connection = self.connection(upload_url)
152
-
153
- options = {}
154
- options[:upload_id] = upload_id
155
- # ipa field is used both for .apk and .ipa files
156
- options[:ipa] = Faraday::UploadIO.new(file, 'application/octet-stream') if file && File.exist?(file)
157
-
158
- response = connection.post do |req|
159
- req.headers['internal-request-source'] = "fastlane"
160
- req.body = options
161
- end
162
-
163
- case response.status
164
- when 200...300
165
- UI.message("Binary uploaded")
166
- self.update_release_upload(api_token, owner_name, app_name, upload_id, 'committed')
167
- else
168
- UI.error("Error uploading binary #{response.status}: #{response.body}")
169
- self.update_release_upload(api_token, owner_name, app_name, upload_id, 'aborted')
170
- UI.error("Release aborted")
171
- false
172
- end
173
- end
174
-
175
- # Commits or aborts the upload process for a release
176
- def self.update_release_upload(api_token, owner_name, app_name, upload_id, status)
177
- connection = self.connection
178
-
179
- response = connection.patch do |req|
180
- req.url("/v0.1/apps/#{owner_name}/#{app_name}/release_uploads/#{upload_id}")
181
- req.headers['X-API-Token'] = api_token
182
- req.headers['internal-request-source'] = "fastlane"
183
- req.body = {
184
- "status" => status
185
- }
186
- end
187
-
188
- case response.status
189
- when 200...300
190
- UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
191
- response.body
192
- else
193
- UI.error("Error #{response.status}: #{response.body}")
194
- false
195
- end
196
- end
197
-
198
- # get existing release
199
- def self.get_release(api_token, release_url)
200
- connection = self.connection
201
- response = connection.get do |req|
202
- req.url("/#{release_url}")
203
- req.headers['X-API-Token'] = api_token
204
- req.headers['internal-request-source'] = "fastlane"
205
- end
206
-
207
- case response.status
208
- when 200...300
209
- release = response.body
210
- UI.message("DEBUG: #{JSON.pretty_generate(release)}") if ENV['DEBUG']
211
- release
212
- when 404
213
- UI.error("Not found, invalid release url")
214
- false
215
- else
216
- UI.error("Error fetching information about release #{response.status}: #{response.body}")
217
- false
218
- end
219
- end
220
-
221
- # add release to distribution group
222
- def self.add_to_group(api_token, release_url, group_name, release_notes = '')
223
- connection = self.connection
224
-
225
- response = connection.patch do |req|
226
- req.url("/#{release_url}")
227
- req.headers['X-API-Token'] = api_token
228
- req.headers['internal-request-source'] = "fastlane"
229
- req.body = {
230
- "distribution_group_name" => group_name,
231
- "release_notes" => release_notes
232
- }
233
- end
234
-
235
- case response.status
236
- when 200...300
237
- # get full release info
238
- release = self.get_release(api_token, release_url)
239
- return false unless release
240
- download_url = release['download_url']
241
-
242
- UI.message("DEBUG: #{JSON.pretty_generate(release)}") if ENV['DEBUG']
243
-
244
- Actions.lane_context[SharedValues::APPCENTER_DOWNLOAD_LINK] = download_url
245
- Actions.lane_context[SharedValues::APPCENTER_BUILD_INFORMATION] = release
246
-
247
- UI.message("Public Download URL: #{download_url}") if download_url
248
- UI.success("Release #{release['short_version']} was successfully distributed to group \"#{group_name}\"")
249
-
250
- release
251
- when 404
252
- UI.error("Not found, invalid distribution group name")
253
- false
254
- else
255
- UI.error("Error adding to group #{response.status}: #{response.body}")
256
- false
257
- end
258
- end
259
-
260
8
  # run whole upload process for dSYM files
261
9
  def self.run_dsym_upload(params)
262
10
  values = params.values
@@ -289,14 +37,14 @@ module Fastlane
289
37
  values[:dsym_path] = dsym_path
290
38
 
291
39
  UI.message("Starting dSYM upload...")
292
- dsym_upload_details = self.create_dsym_upload(api_token, owner_name, app_name)
40
+ dsym_upload_details = Helper::AppcenterHelper.create_dsym_upload(api_token, owner_name, app_name)
293
41
 
294
42
  if dsym_upload_details
295
43
  symbol_upload_id = dsym_upload_details['symbol_upload_id']
296
44
  upload_url = dsym_upload_details['upload_url']
297
45
 
298
46
  UI.message("Uploading dSYM...")
299
- self.upload_dsym(api_token, owner_name, app_name, dsym_path, symbol_upload_id, upload_url)
47
+ Helper::AppcenterHelper.upload_dsym(api_token, owner_name, app_name, dsym_path, symbol_upload_id, upload_url)
300
48
  end
301
49
  end
302
50
  end
@@ -308,6 +56,8 @@ module Fastlane
308
56
  owner_name = params[:owner_name]
309
57
  app_name = params[:app_name]
310
58
  group = params[:group]
59
+ mandatory_update = params[:mandatory_update]
60
+ notify_testers = params[:notify_testers]
311
61
  release_notes = params[:release_notes]
312
62
  should_clip = params[:should_clip]
313
63
  release_notes_link = params[:release_notes_link]
@@ -333,48 +83,39 @@ module Fastlane
333
83
  UI.user_error!("No Distribute Group given, pass using `group: 'group name'`") unless group && !group.empty?
334
84
 
335
85
  UI.message("Starting release upload...")
336
- upload_details = self.create_release_upload(api_token, owner_name, app_name)
86
+ upload_details = Helper::AppcenterHelper.create_release_upload(api_token, owner_name, app_name)
337
87
  if upload_details
338
88
  upload_id = upload_details['upload_id']
339
89
  upload_url = upload_details['upload_url']
340
90
 
341
91
  UI.message("Uploading release binary...")
342
- uploaded = self.upload_build(api_token, owner_name, app_name, file, upload_id, upload_url)
92
+ uploaded = Helper::AppcenterHelper.upload_build(api_token, owner_name, app_name, file, upload_id, upload_url)
343
93
 
344
94
  if uploaded
345
- release_url = uploaded['release_url']
346
- UI.message("Release committed")
95
+ release_id = uploaded['release_id']
96
+ UI.message("Release '#{release_id}' committed")
97
+
98
+ Helper::AppcenterHelper.update_release(api_token, owner_name, app_name, release_id, release_notes)
99
+
347
100
  groups = group.split(',')
348
101
  groups.each do |group_name|
349
- self.add_to_group(api_token, release_url, group_name, release_notes)
102
+ group = Helper::AppcenterHelper.get_group(api_token, owner_name, app_name, group_name)
103
+ if group
104
+ group_id = group['id']
105
+ distributed_release = Helper::AppcenterHelper.add_to_group(api_token, owner_name, app_name, release_id, group_id, mandatory_update, notify_testers)
106
+ if distributed_release
107
+ UI.success("Release #{distributed_release['short_version']} was successfully distributed to group \"#{group_name}\"")
108
+ else
109
+ UI.error("Release '#{release_id}' was not found")
110
+ end
111
+ else
112
+ UI.error("Group '#{group_name}' was not found")
113
+ end
350
114
  end
351
115
  end
352
116
  end
353
117
  end
354
118
 
355
- # returns true if app exists, false in case of 404 and error otherwise
356
- def self.get_app(api_token, owner_name, app_name)
357
- connection = self.connection
358
-
359
- response = connection.get do |req|
360
- req.url("/v0.1/apps/#{owner_name}/#{app_name}")
361
- req.headers['X-API-Token'] = api_token
362
- req.headers['internal-request-source'] = "fastlane"
363
- end
364
-
365
- case response.status
366
- when 200...300
367
- UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
368
- true
369
- when 404
370
- UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
371
- false
372
- else
373
- UI.error("Error #{response.status}: #{response.body}")
374
- false
375
- end
376
- end
377
-
378
119
  # checks app existance, if ther is no such - creates it
379
120
  def self.get_or_create_app(params)
380
121
  api_token = params[:api_token]
@@ -386,37 +127,14 @@ module Fastlane
386
127
  "iOS" => ['Objective-C-Swift', 'React-Native', 'Xamarin']
387
128
  }
388
129
 
389
- if self.get_app(api_token, owner_name, app_name)
130
+ if Helper::AppcenterHelper.get_app(api_token, owner_name, app_name)
390
131
  true
391
132
  else
392
133
  if Helper.test? || UI.confirm("App with name #{app_name} not found, create one?")
393
- connection = self.connection
394
-
395
134
  os = Helper.test? ? "Android" : UI.select("Select OS", ["Android", "iOS"])
396
135
  platform = Helper.test? ? "Java" : UI.select("Select Platform", platforms[os])
397
136
 
398
- response = connection.post do |req|
399
- req.url("/v0.1/apps")
400
- req.headers['X-API-Token'] = api_token
401
- req.headers['internal-request-source'] = "fastlane"
402
- req.body = {
403
- "display_name" => app_name,
404
- "name" => app_name,
405
- "os" => os,
406
- "platform" => platform
407
- }
408
- end
409
-
410
- case response.status
411
- when 200...300
412
- created = response.body
413
- UI.message("DEBUG: #{JSON.pretty_generate(created)}") if ENV['DEBUG']
414
- UI.success("Created #{os}/#{platform} app with name \"#{created['name']}\"")
415
- true
416
- else
417
- UI.error("Error creating app #{response.status}: #{response.body}")
418
- false
419
- end
137
+ Helper::AppcenterHelper.create_app(api_token, owner_name, app_name, os, platform)
420
138
  else
421
139
  UI.error("Lane aborted")
422
140
  false
@@ -446,9 +164,7 @@ module Fastlane
446
164
  end
447
165
 
448
166
  def self.details
449
- [
450
- "Symbols will also be uploaded automatically if a `app.dSYM.zip` file is found next to `app.ipa`. In case it is located in a different place you can specify the path explicitly in `:dsym` parameter."
451
- ]
167
+ "Symbols will also be uploaded automatically if a `app.dSYM.zip` file is found next to `app.ipa`. In case it is located in a different place you can specify the path explicitly in `:dsym` parameter."
452
168
  end
453
169
 
454
170
  def self.available_options
@@ -536,6 +252,20 @@ module Fastlane
536
252
  optional: true,
537
253
  type: String),
538
254
 
255
+ FastlaneCore::ConfigItem.new(key: :mandatory_update,
256
+ env_name: "APPCENTER_DISTRIBUTE_MANDATORY_UPDATE",
257
+ description: "Require users to update to this release",
258
+ optional: true,
259
+ is_string: false,
260
+ default_value: false),
261
+
262
+ FastlaneCore::ConfigItem.new(key: :notify_testers,
263
+ env_name: "APPCENTER_DISTRIBUTE_NOTIFY_TESTERS",
264
+ description: "Send email notification about release",
265
+ optional: true,
266
+ is_string: false,
267
+ default_value: false),
268
+
539
269
  FastlaneCore::ConfigItem.new(key: :release_notes,
540
270
  env_name: "APPCENTER_DISTRIBUTE_RELEASE_NOTES",
541
271
  description: "Release notes",
@@ -545,7 +275,7 @@ module Fastlane
545
275
 
546
276
  FastlaneCore::ConfigItem.new(key: :should_clip,
547
277
  env_name: "APPCENTER_DISTRIBUTE_RELEASE_NOTES_CLIPPING",
548
- description: "Clip release notes if its lenght is more then #{Constants::MAX_RELEASE_NOTES_LENGTH}, true by default",
278
+ description: "Clip release notes if its length is more then #{Constants::MAX_RELEASE_NOTES_LENGTH}, true by default",
549
279
  optional: true,
550
280
  is_string: false,
551
281
  default_value: true),
@@ -593,4 +323,3 @@ module Fastlane
593
323
  end
594
324
  end
595
325
  end
596
- # rubocop:enable Metrics/ClassLength
@@ -1,11 +1,370 @@
1
1
  module Fastlane
2
2
  module Helper
3
+ module SharedValues
4
+ APPCENTER_DOWNLOAD_LINK = :APPCENTER_DOWNLOAD_LINK
5
+ APPCENTER_BUILD_INFORMATION = :APPCENTER_BUILD_INFORMATION
6
+ end
7
+
3
8
  class AppcenterHelper
4
- # class methods that you define here become available in your action
5
- # as `Helper::AppcenterHelper.your_method`
6
- #
7
- def self.show_message
8
- UI.message("Hello from the appcenter plugin helper!")
9
+
10
+ # create request
11
+ def self.connection(upload_url = false, dsym = false)
12
+ require 'faraday'
13
+ require 'faraday_middleware'
14
+
15
+ options = {
16
+ url: upload_url ? upload_url : "https://api.appcenter.ms"
17
+ }
18
+
19
+ Faraday.new(options) do |builder|
20
+ if upload_url
21
+ builder.request :multipart unless dsym
22
+ builder.request :url_encoded unless dsym
23
+ else
24
+ builder.request :json
25
+ end
26
+ builder.response :json, content_type: /\bjson$/
27
+ builder.use FaradayMiddleware::FollowRedirects
28
+ builder.adapter :net_http
29
+ end
30
+ end
31
+
32
+ # creates new release upload
33
+ # returns:
34
+ # upload_id
35
+ # upload_url
36
+ def self.create_release_upload(api_token, owner_name, app_name)
37
+ connection = self.connection
38
+
39
+ response = connection.post do |req|
40
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/release_uploads")
41
+ req.headers['X-API-Token'] = api_token
42
+ req.headers['internal-request-source'] = "fastlane"
43
+ req.body = {}
44
+ end
45
+
46
+ case response.status
47
+ when 200...300
48
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
49
+ response.body
50
+ when 401
51
+ UI.user_error!("Auth Error, provided invalid token")
52
+ false
53
+ when 404
54
+ UI.error("Not found, invalid owner or application name")
55
+ false
56
+ else
57
+ UI.error("Error #{response.status}: #{response.body}")
58
+ false
59
+ end
60
+ end
61
+
62
+ # creates new dSYM upload in appcenter
63
+ # returns:
64
+ # symbol_upload_id
65
+ # upload_url
66
+ # expiration_date
67
+ def self.create_dsym_upload(api_token, owner_name, app_name)
68
+ connection = self.connection
69
+
70
+ response = connection.post do |req|
71
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/symbol_uploads")
72
+ req.headers['X-API-Token'] = api_token
73
+ req.headers['internal-request-source'] = "fastlane"
74
+ req.body = {
75
+ symbol_type: 'Apple'
76
+ }
77
+ end
78
+
79
+ case response.status
80
+ when 200...300
81
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
82
+ response.body
83
+ when 401
84
+ UI.user_error!("Auth Error, provided invalid token")
85
+ false
86
+ when 404
87
+ UI.error("Not found, invalid owner or application name")
88
+ false
89
+ else
90
+ UI.error("Error #{response.status}: #{response.body}")
91
+ false
92
+ end
93
+ end
94
+
95
+ # committs or aborts dsym upload
96
+ def self.update_dsym_upload(api_token, owner_name, app_name, symbol_upload_id, status)
97
+ connection = self.connection
98
+
99
+ response = connection.patch do |req|
100
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/symbol_uploads/#{symbol_upload_id}")
101
+ req.headers['X-API-Token'] = api_token
102
+ req.headers['internal-request-source'] = "fastlane"
103
+ req.body = {
104
+ "status" => status
105
+ }
106
+ end
107
+
108
+ case response.status
109
+ when 200...300
110
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
111
+ response.body
112
+ else
113
+ UI.error("Error #{response.status}: #{response.body}")
114
+ false
115
+ end
116
+ end
117
+
118
+ # upload dSYM files to specified upload url
119
+ # if succeed, then commits the upload
120
+ # otherwise aborts
121
+ def self.upload_dsym(api_token, owner_name, app_name, dsym, symbol_upload_id, upload_url)
122
+ connection = self.connection(upload_url, true)
123
+
124
+ response = connection.put do |req|
125
+ req.headers['x-ms-blob-type'] = "BlockBlob"
126
+ req.headers['Content-Length'] = File.size(dsym).to_s
127
+ req.headers['internal-request-source'] = "fastlane"
128
+ req.body = Faraday::UploadIO.new(dsym, 'application/octet-stream') if dsym && File.exist?(dsym)
129
+ end
130
+
131
+ case response.status
132
+ when 200...300
133
+ self.update_dsym_upload(api_token, owner_name, app_name, symbol_upload_id, 'committed')
134
+ UI.success("dSYM uploaded")
135
+ else
136
+ UI.error("Error uploading dSYM #{response.status}: #{response.body}")
137
+ self.update_dsym_upload(api_token, owner_name, app_name, symbol_upload_id, 'aborted')
138
+ UI.error("dSYM upload aborted")
139
+ false
140
+ end
141
+ end
142
+
143
+ # upload binary for specified upload_url
144
+ # if succeed, then commits the release
145
+ # otherwise aborts
146
+ def self.upload_build(api_token, owner_name, app_name, file, upload_id, upload_url)
147
+ connection = self.connection(upload_url)
148
+
149
+ options = {}
150
+ options[:upload_id] = upload_id
151
+ # ipa field is used both for .apk and .ipa files
152
+ options[:ipa] = Faraday::UploadIO.new(file, 'application/octet-stream') if file && File.exist?(file)
153
+
154
+ response = connection.post do |req|
155
+ req.headers['internal-request-source'] = "fastlane"
156
+ req.body = options
157
+ end
158
+
159
+ case response.status
160
+ when 200...300
161
+ UI.message("Binary uploaded")
162
+ self.update_release_upload(api_token, owner_name, app_name, upload_id, 'committed')
163
+ else
164
+ UI.error("Error uploading binary #{response.status}: #{response.body}")
165
+ self.update_release_upload(api_token, owner_name, app_name, upload_id, 'aborted')
166
+ UI.error("Release aborted")
167
+ false
168
+ end
169
+ end
170
+
171
+ # Commits or aborts the upload process for a release
172
+ def self.update_release_upload(api_token, owner_name, app_name, upload_id, status)
173
+ connection = self.connection
174
+
175
+ response = connection.patch do |req|
176
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/release_uploads/#{upload_id}")
177
+ req.headers['X-API-Token'] = api_token
178
+ req.headers['internal-request-source'] = "fastlane"
179
+ req.body = {
180
+ "status" => status
181
+ }
182
+ end
183
+
184
+ case response.status
185
+ when 200...300
186
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
187
+ response.body
188
+ else
189
+ UI.error("Error #{response.status}: #{response.body}")
190
+ false
191
+ end
192
+ end
193
+
194
+ # get existing release
195
+ def self.get_release(api_token, owner_name, app_name, release_id)
196
+ connection = self.connection
197
+ response = connection.get do |req|
198
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/releases/#{release_id}")
199
+ req.headers['X-API-Token'] = api_token
200
+ req.headers['internal-request-source'] = "fastlane"
201
+ end
202
+
203
+ case response.status
204
+ when 200...300
205
+ release = response.body
206
+ UI.message("DEBUG: #{JSON.pretty_generate(release)}") if ENV['DEBUG']
207
+ release
208
+ when 404
209
+ UI.error("Not found, invalid release url")
210
+ false
211
+ else
212
+ UI.error("Error fetching information about release #{response.status}: #{response.body}")
213
+ false
214
+ end
215
+ end
216
+
217
+ # get distribution group
218
+ def self.get_group(api_token, owner_name, app_name, group_name)
219
+ connection = self.connection
220
+
221
+ response = connection.get do |req|
222
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/distribution_groups/#{group_name}")
223
+ req.headers['X-API-Token'] = api_token
224
+ req.headers['internal-request-source'] = "fastlane"
225
+ end
226
+
227
+ case response.status
228
+ when 200...300
229
+ group = response.body
230
+ UI.message("DEBUG: received group #{JSON.pretty_generate(group)}") if ENV['DEBUG']
231
+ group
232
+ when 404
233
+ UI.error("Not found, invalid distribution group name")
234
+ false
235
+ else
236
+ UI.error("Error getting group #{response.status}: #{response.body}")
237
+ false
238
+ end
239
+ end
240
+
241
+ # add release to destination
242
+ def self.update_release(api_token, owner_name, app_name, release_id, release_notes = '')
243
+ connection = self.connection
244
+
245
+ response = connection.put do |req|
246
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/releases/#{release_id}")
247
+ req.headers['X-API-Token'] = api_token
248
+ req.headers['internal-request-source'] = "fastlane"
249
+ req.body = {
250
+ "release_notes" => release_notes
251
+ }
252
+ end
253
+
254
+ case response.status
255
+ when 200...300
256
+ # get full release info
257
+ release = self.get_release(api_token, owner_name, app_name, release_id)
258
+ return false unless release
259
+ download_url = release['download_url']
260
+
261
+ UI.message("DEBUG: #{JSON.pretty_generate(release)}") if ENV['DEBUG']
262
+
263
+ Actions.lane_context[SharedValues::APPCENTER_DOWNLOAD_LINK] = download_url
264
+ Actions.lane_context[SharedValues::APPCENTER_BUILD_INFORMATION] = release
265
+
266
+ UI.message("Release #{release['short_version']} was successfully updated")
267
+
268
+ release
269
+ when 404
270
+ UI.error("Not found, invalid release id")
271
+ false
272
+ else
273
+ UI.error("Error adding updating release #{response.status}: #{response.body}")
274
+ false
275
+ end
276
+ end
277
+
278
+ # add release to distribution group
279
+ def self.add_to_group(api_token, owner_name, app_name, release_id, group_id, mandatory_update = false, notify_testers = false)
280
+ connection = self.connection
281
+
282
+ UI.message("DEBUG: getting #{release_id}") if ENV['DEBUG']
283
+
284
+ response = connection.post do |req|
285
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}/releases/#{release_id}/groups")
286
+ req.headers['X-API-Token'] = api_token
287
+ req.headers['internal-request-source'] = "fastlane"
288
+ req.body = {
289
+ "id" => group_id,
290
+ "mandatory_update" => mandatory_update,
291
+ "notify_testers" => notify_testers
292
+ }
293
+ end
294
+
295
+ case response.status
296
+ when 200...300
297
+ # get full release info
298
+ release = self.get_release(api_token, owner_name, app_name, release_id)
299
+ return false unless release
300
+ download_url = release['download_url']
301
+
302
+ UI.message("DEBUG: received release #{JSON.pretty_generate(release)}") if ENV['DEBUG']
303
+
304
+ Actions.lane_context[SharedValues::APPCENTER_DOWNLOAD_LINK] = download_url
305
+ Actions.lane_context[SharedValues::APPCENTER_BUILD_INFORMATION] = release
306
+
307
+ UI.message("Public Download URL: #{download_url}") if download_url
308
+
309
+ release
310
+ when 404
311
+ UI.error("Not found, invalid distribution group name")
312
+ false
313
+ else
314
+ UI.error("Error adding to group #{response.status}: #{response.body}")
315
+ false
316
+ end
317
+ end
318
+
319
+ # returns true if app exists, false in case of 404 and error otherwise
320
+ def self.get_app(api_token, owner_name, app_name)
321
+ connection = self.connection
322
+
323
+ response = connection.get do |req|
324
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}")
325
+ req.headers['X-API-Token'] = api_token
326
+ req.headers['internal-request-source'] = "fastlane"
327
+ end
328
+
329
+ case response.status
330
+ when 200...300
331
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
332
+ true
333
+ when 404
334
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
335
+ false
336
+ else
337
+ UI.error("Error #{response.status}: #{response.body}")
338
+ false
339
+ end
340
+ end
341
+
342
+ # returns true if app exists, false in case of 404 and error otherwise
343
+ def self.create_app(api_token, owner_name, app_name, os, platform)
344
+ connection = self.connection
345
+
346
+ response = connection.post do |req|
347
+ req.url("/v0.1/apps")
348
+ req.headers['X-API-Token'] = api_token
349
+ req.headers['internal-request-source'] = "fastlane"
350
+ req.body = {
351
+ "display_name" => app_name,
352
+ "name" => app_name,
353
+ "os" => os,
354
+ "platform" => platform
355
+ }
356
+ end
357
+
358
+ case response.status
359
+ when 200...300
360
+ created = response.body
361
+ UI.message("DEBUG: #{JSON.pretty_generate(created)}") if ENV['DEBUG']
362
+ UI.success("Created #{os}/#{platform} app with name \"#{created['name']}\"")
363
+ true
364
+ else
365
+ UI.error("Error creating app #{response.status}: #{response.body}")
366
+ false
367
+ end
9
368
  end
10
369
  end
11
370
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Appcenter
3
- VERSION = "0.1.7"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-appcenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Microsoft Corporation
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-12 00:00:00.000000000 Z
11
+ date: 2019-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
126
  version: '0'
127
127
  requirements: []
128
128
  rubyforge_project:
129
- rubygems_version: 2.6.12
129
+ rubygems_version: 2.7.6
130
130
  signing_key:
131
131
  specification_version: 4
132
132
  summary: Fastlane plugin for App Center