fastlane-plugin-appcenter 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 48df8a17edb752b7e11b38125b5e205971e9e2be
4
+ data.tar.gz: 7a0672dd1a6250ce6225a42c23cb30ac74e82177
5
+ SHA512:
6
+ metadata.gz: 29d4b4696c8cacdee4e2ad44ea52b806a77ff60fabee8ef4da0516688016f855caa2895a367348cdc8fffb9c750603b89098c45e77d295dcd7fd5295a0859b26
7
+ data.tar.gz: 69e9c5a5bf119ad4afbced987b4522384ab9c56469e52d3c49d043d5d00e3bc3508ed6bbe955877830ae00512e930376165f73950b2ef252124bbf26328dec54
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Microsoft Corporation. All rights reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # appcenter plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-appcenter)
4
+ [![Gem Version](https://badge.fury.io/rb/fastlane-plugin-appcenter.svg)](https://badge.fury.io/rb/fastlane-plugin-appcenter)
5
+ [![Build Status](https://travis-ci.org/Microsoft/fastlane-plugin-appcenter.svg?branch=master)](https://travis-ci.org/Microsoft/fastlane-plugin-appcenter)
6
+
7
+ ## Getting Started
8
+
9
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-appcenter`, add it to your project by running:
10
+
11
+ ```bash
12
+ fastlane add_plugin appcenter
13
+ ```
14
+
15
+ ## About appcenter
16
+
17
+ Plugin for [App Center](https://appcenter.ms). Provides `appcenter_upload` action for [release distribution](https://docs.microsoft.com/en-us/appcenter/distribution/uploading) and [dSYM uploads](https://docs.microsoft.com/en-us/appcenter/crashes/ios)
18
+
19
+ ## Usage
20
+
21
+ Obtain an [API token](https://docs.microsoft.com/en-us/appcenter/api-docs/). API Token is used for authentication for all App Center API calls.
22
+
23
+ ```ruby
24
+ appcenter_upload(
25
+ api_token: "<appcenter token>",
26
+ owner_name: "<your appcenter account name>",
27
+ app_name: "<your app name>",
28
+ apk: "<path to android build binary>"
29
+ )
30
+ ```
31
+
32
+ ## Example
33
+
34
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
35
+
36
+ Sample uses `.env` for setting private variables like API token, owner name, .etc. You need to replace it in `Fastfile` by your own values.
37
+
38
+ There are three examples in `test` lane:
39
+ - upload release for android with minimum required parameters
40
+ - upload release for ios with all set parameters
41
+ - upload only dSYM file for ios
42
+
43
+ ## Run tests for this plugin
44
+
45
+ To run both the tests, and code style validation, run
46
+
47
+ ```
48
+ rake
49
+ ```
50
+
51
+ To automatically fix many of the styling issues, use
52
+ ```
53
+ rubocop -a
54
+ ```
55
+
56
+ ## Issues and Feedback
57
+
58
+ For any other issues and feedback about this plugin, please submit it to this repository.
59
+
60
+ ## Troubleshooting
61
+
62
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
63
+
64
+ ## Using _fastlane_ Plugins
65
+
66
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
67
+
68
+ ## About _fastlane_
69
+
70
+ _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
71
+
72
+ ## Contributing
73
+
74
+ This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
75
+
76
+ ## Contact
77
+
78
+ ### Intercom
79
+
80
+ If you have further questions, want to provide feedback or you are running into issues, log in to the [App Center](https://appcenter.ms) portal and use the blue Intercom button on the bottom right to start a conversation with us.
81
+
82
+ ### Twitter
83
+
84
+ We're on Twitter as [@appcenter](https://www.twitter.com/vsappcenter).
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/appcenter/version'
2
+
3
+ module Fastlane
4
+ module Appcenter
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::Appcenter.all_classes.each do |current|
15
+ require current
16
+ end
@@ -0,0 +1,535 @@
1
+ # rubocop:disable Metrics/ClassLength
2
+ module Fastlane
3
+ module Actions
4
+ module SharedValues
5
+ APPCENTER_DOWNLOAD_LINK = :APPCENTER_DOWNLOAD_LINK
6
+ APPCENTER_BUILD_INFORMATION = :APPCENTER_BUILD_INFORMATION
7
+ end
8
+
9
+ class AppcenterUploadAction < Action
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
+ # add release to distribution group
195
+ def self.add_to_group(api_token, release_url, group_name, release_notes = '')
196
+ connection = self.connection
197
+
198
+ response = connection.patch do |req|
199
+ req.url("/#{release_url}")
200
+ req.headers['X-API-Token'] = api_token
201
+ req.headers['internal-request-source'] = "fastlane"
202
+ req.body = {
203
+ "distribution_group_name" => group_name,
204
+ "release_notes" => release_notes
205
+ }
206
+ end
207
+
208
+ case response.status
209
+ when 200...300
210
+ release = response.body
211
+ download_url = release['download_url']
212
+
213
+ UI.message("DEBUG: #{JSON.pretty_generate(release)}") if ENV['DEBUG']
214
+
215
+ Actions.lane_context[SharedValues::APPCENTER_DOWNLOAD_LINK] = download_url
216
+ Actions.lane_context[SharedValues::APPCENTER_BUILD_INFORMATION] = release
217
+
218
+ UI.message("Public Download URL: #{download_url}") if download_url
219
+ UI.success("Release #{release['short_version']} was successfully distributed")
220
+
221
+ release
222
+ when 404
223
+ UI.error("Not found, invalid distribution group name")
224
+ false
225
+ else
226
+ UI.error("Error adding to group #{response.status}: #{response.body}")
227
+ false
228
+ end
229
+ end
230
+
231
+ # run whole upload process for dSYM files
232
+ def self.run_dsym_upload(params)
233
+ values = params.values
234
+ api_token = params[:api_token]
235
+ owner_name = params[:owner_name]
236
+ app_name = params[:app_name]
237
+ file = params[:ipa]
238
+ dsym = params[:dsym]
239
+
240
+ dsym_path = nil
241
+ if dsym
242
+ # we can use dsym parameter only if build file is ipa
243
+ dsym_path = dsym if !file || File.extname(file) == '.ipa'
244
+ else
245
+ # if dsym is note set, but build is ipa - check default path
246
+ if file && File.exist?(file) && File.extname(file) == '.ipa'
247
+ dsym_path = file.to_s.gsub('.ipa', '.dSYM.zip')
248
+ UI.message("dSYM is found")
249
+ end
250
+ end
251
+
252
+ # if we provided valid dsym path, or <ipa_path>.dSYM.zip was found, start dSYM upload
253
+ if dsym_path && File.exist?(dsym_path)
254
+ if File.directory?(dsym_path)
255
+ UI.message("dSYM path is folder, zipping...")
256
+ dsym_path = Actions::ZipAction.run(path: dsym, output_path: dsym + ".zip")
257
+ UI.message("dSYM files zipped")
258
+ end
259
+
260
+ values[:dsym_path] = dsym_path
261
+
262
+ UI.message("Starting dSYM upload...")
263
+ dsym_upload_details = self.create_dsym_upload(api_token, owner_name, app_name)
264
+
265
+ if dsym_upload_details
266
+ symbol_upload_id = dsym_upload_details['symbol_upload_id']
267
+ upload_url = dsym_upload_details['upload_url']
268
+
269
+ UI.message("Uploading dSYM...")
270
+ self.upload_dsym(api_token, owner_name, app_name, dsym_path, symbol_upload_id, upload_url)
271
+ end
272
+ end
273
+ end
274
+
275
+ # run whole upload process for release
276
+ def self.run_release_upload(params)
277
+ api_token = params[:api_token]
278
+ owner_name = params[:owner_name]
279
+ app_name = params[:app_name]
280
+ group = params[:group]
281
+
282
+ file = [
283
+ params[:ipa],
284
+ params[:apk]
285
+ ].detect { |e| !e.to_s.empty? }
286
+
287
+ UI.user_error!("Couldn't find build file at path '#{file}'") unless file && File.exist?(file)
288
+ UI.user_error!("No Distribute Group given, pass using `group: 'group name'`") unless group && !group.empty?
289
+
290
+ UI.message("Starting release upload...")
291
+ upload_details = self.create_release_upload(api_token, owner_name, app_name)
292
+ if upload_details
293
+ upload_id = upload_details['upload_id']
294
+ upload_url = upload_details['upload_url']
295
+
296
+ UI.message("Uploading release binary...")
297
+ uploaded = self.upload_build(api_token, owner_name, app_name, file, upload_id, upload_url)
298
+
299
+ if uploaded
300
+ release_url = uploaded['release_url']
301
+ UI.message("Release committed")
302
+ self.add_to_group(api_token, release_url, group, params[:release_notes])
303
+ end
304
+ end
305
+ end
306
+
307
+ # returns true if app exists, false in case of 404 and error otherwise
308
+ def self.get_app(api_token, owner_name, app_name)
309
+ connection = self.connection
310
+
311
+ response = connection.get do |req|
312
+ req.url("/v0.1/apps/#{owner_name}/#{app_name}")
313
+ req.headers['X-API-Token'] = api_token
314
+ req.headers['internal-request-source'] = "fastlane"
315
+ end
316
+
317
+ case response.status
318
+ when 200...300
319
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
320
+ true
321
+ when 404
322
+ UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
323
+ false
324
+ else
325
+ UI.error("Error #{response.status}: #{response.body}")
326
+ false
327
+ end
328
+ end
329
+
330
+ # checks app existance, if ther is no such - creates it
331
+ def self.get_or_create_app(params)
332
+ api_token = params[:api_token]
333
+ owner_name = params[:owner_name]
334
+ app_name = params[:app_name]
335
+
336
+ platforms = {
337
+ "Android" => ['Java', 'React-Native', 'Xamarin'],
338
+ "iOS" => ['Objective-C-Swift', 'React-Native', 'Xamarin']
339
+ }
340
+
341
+ if self.get_app(api_token, owner_name, app_name)
342
+ true
343
+ else
344
+ if Helper.test? || UI.confirm("App with name #{app_name} not found, create one?")
345
+ connection = self.connection
346
+
347
+ os = Helper.test? ? "Android" : UI.select("Select OS", ["Android", "iOS"])
348
+ platform = Helper.test? ? "Java" : UI.select("Select Platform", platforms[os])
349
+
350
+ response = connection.post do |req|
351
+ req.url("/v0.1/apps")
352
+ req.headers['X-API-Token'] = api_token
353
+ req.headers['internal-request-source'] = "fastlane"
354
+ req.body = {
355
+ "display_name" => app_name,
356
+ "name" => app_name,
357
+ "os" => os,
358
+ "platform" => platform
359
+ }
360
+ end
361
+
362
+ case response.status
363
+ when 200...300
364
+ created = response.body
365
+ UI.message("DEBUG: #{JSON.pretty_generate(created)}") if ENV['DEBUG']
366
+ UI.success("Created #{os}/#{platform} app with name \"#{created['name']}\"")
367
+ true
368
+ else
369
+ UI.error("Error creating app #{response.status}: #{response.body}")
370
+ false
371
+ end
372
+ else
373
+ UI.error("Lane aborted")
374
+ false
375
+ end
376
+ end
377
+ end
378
+
379
+ def self.run(params)
380
+ values = params.values
381
+ upload_dsym_only = params[:upload_dsym_only]
382
+
383
+ # if app found or successfully created
384
+ if self.get_or_create_app(params)
385
+ self.run_release_upload(params) unless upload_dsym_only
386
+ self.run_dsym_upload(params)
387
+ end
388
+
389
+ return values if Helper.test?
390
+ end
391
+
392
+ def self.description
393
+ "Distribute new release to App Center"
394
+ end
395
+
396
+ def self.authors
397
+ ["Microsoft"]
398
+ end
399
+
400
+ def self.details
401
+ [
402
+ "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."
403
+ ]
404
+ end
405
+
406
+ def self.available_options
407
+ [
408
+ FastlaneCore::ConfigItem.new(key: :api_token,
409
+ env_name: "APPCENTER_API_TOKEN",
410
+ description: "API Token for App Center",
411
+ optional: false,
412
+ type: String,
413
+ verify_block: proc do |value|
414
+ UI.user_error!("No API token for App Center given, pass using `api_token: 'token'`") unless value && !value.empty?
415
+ end),
416
+
417
+ FastlaneCore::ConfigItem.new(key: :owner_name,
418
+ env_name: "APPCENTER_OWNER_NAME",
419
+ description: "Owner name",
420
+ optional: false,
421
+ type: String,
422
+ verify_block: proc do |value|
423
+ UI.user_error!("No Owner name for App Center given, pass using `owner_name: 'name'`") unless value && !value.empty?
424
+ end),
425
+
426
+ FastlaneCore::ConfigItem.new(key: :app_name,
427
+ env_name: "APPCENTER_APP_NAME",
428
+ description: "App name. If there is no app with such name, you will be prompted to create one",
429
+ optional: false,
430
+ type: String,
431
+ verify_block: proc do |value|
432
+ UI.user_error!("No App name given, pass using `app_name: 'app name'`") unless value && !value.empty?
433
+ end),
434
+
435
+ FastlaneCore::ConfigItem.new(key: :apk,
436
+ env_name: "APPCENTER_DISTRIBUTE_APK",
437
+ description: "Build release path for android build",
438
+ default_value: Actions.lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH],
439
+ optional: true,
440
+ type: String,
441
+ conflicting_options: [:ipa],
442
+ conflict_block: proc do |value|
443
+ UI.user_error!("You can't use 'apk' and '#{value.key}' options in one run")
444
+ end,
445
+ verify_block: proc do |value|
446
+ accepted_formats = [".apk"]
447
+ UI.user_error!("Only \".apk\" formats are allowed, you provided \"#{File.extname(value)}\"") unless accepted_formats.include? File.extname(value)
448
+ end),
449
+
450
+ FastlaneCore::ConfigItem.new(key: :ipa,
451
+ env_name: "APPCENTER_DISTRIBUTE_IPA",
452
+ description: "Build release path for ios build",
453
+ default_value: Actions.lane_context[SharedValues::IPA_OUTPUT_PATH],
454
+ optional: true,
455
+ type: String,
456
+ conflicting_options: [:apk],
457
+ conflict_block: proc do |value|
458
+ UI.user_error!("You can't use 'ipa' and '#{value.key}' options in one run")
459
+ end,
460
+ verify_block: proc do |value|
461
+ accepted_formats = [".ipa"]
462
+ UI.user_error!("Only \".ipa\" formats are allowed, you provided \"#{File.extname(value)}\"") unless accepted_formats.include? File.extname(value)
463
+ end),
464
+
465
+ FastlaneCore::ConfigItem.new(key: :dsym,
466
+ env_name: "APPCENTER_DISTRIBUTE_DSYM",
467
+ description: "Path to your symbols file. For iOS provide path to app.dSYM.zip",
468
+ default_value: Actions.lane_context[SharedValues::DSYM_OUTPUT_PATH],
469
+ optional: true,
470
+ type: String,
471
+ verify_block: proc do |value|
472
+ if value
473
+ UI.user_error!("Couldn't find dSYM file at path '#{value}'") unless File.exist?(value)
474
+ end
475
+ end),
476
+
477
+ FastlaneCore::ConfigItem.new(key: :upload_dsym_only,
478
+ env_name: "APPCENTER_DISTRIBUTE_UPLOAD_DSYM_ONLY",
479
+ description: "Flag to upload only the dSYM file to App Center",
480
+ optional: true,
481
+ is_string: false,
482
+ default_value: false),
483
+
484
+ FastlaneCore::ConfigItem.new(key: :group,
485
+ env_name: "APPCENTER_DISTRIBUTE_GROUP",
486
+ description: "Distribute group name",
487
+ default_value: "Collaborators",
488
+ optional: true,
489
+ type: String),
490
+
491
+ FastlaneCore::ConfigItem.new(key: :release_notes,
492
+ env_name: "APPCENTER_DISTRIBUTE_RELEASE_NOTES",
493
+ description: "Release notes",
494
+ default_value: Actions.lane_context[SharedValues::FL_CHANGELOG] || "No changelog given",
495
+ optional: true,
496
+ type: String)
497
+ ]
498
+ end
499
+
500
+ def self.output
501
+ [
502
+ ['APPCENTER_DOWNLOAD_LINK', 'The newly generated download link for this build'],
503
+ ['APPCENTER_BUILD_INFORMATION', 'contains all keys/values from the App Center API']
504
+ ]
505
+ end
506
+
507
+ def self.is_supported?(platform)
508
+ true
509
+ end
510
+
511
+ def self.example_code
512
+ [
513
+ 'appcenter_upload(
514
+ api_token: "...",
515
+ owner_name: "appcenter_owner",
516
+ app_name: "testing_app",
517
+ apk: "./app-release.apk",
518
+ group: "Testers",
519
+ release_notes: "release notes"
520
+ )',
521
+ 'appcenter_upload(
522
+ api_token: "...",
523
+ owner_name: "appcenter_owner",
524
+ app_name: "testing_app",
525
+ apk: "./app-release.ipa",
526
+ group: "Testers",
527
+ dsym: "./app.dSYM.zip",
528
+ release_notes: "release notes"
529
+ )'
530
+ ]
531
+ end
532
+ end
533
+ end
534
+ end
535
+ # rubocop:enable Metrics/ClassLength
@@ -0,0 +1,12 @@
1
+ module Fastlane
2
+ module Helper
3
+ 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
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Appcenter
3
+ VERSION = "0.1.4"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-appcenter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Microsoft Corporation
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fastlane
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.29.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.29.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
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: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
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: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - LICENSE
104
+ - README.md
105
+ - lib/fastlane/plugin/appcenter.rb
106
+ - lib/fastlane/plugin/appcenter/actions/appcenter_upload_action.rb
107
+ - lib/fastlane/plugin/appcenter/helper/appcenter_helper.rb
108
+ - lib/fastlane/plugin/appcenter/version.rb
109
+ homepage: https://github.com/Microsoft/fastlane-plugin-appcenter
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.6.12
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Fastlane plugin for App Center
133
+ test_files: []