fastlane-plugin-appcenter 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +83 -25
- data/lib/fastlane/plugin/appcenter/actions/appcenter_fetch_devices_action.rb +138 -0
- data/lib/fastlane/plugin/appcenter/actions/appcenter_upload_action.rb +25 -9
- data/lib/fastlane/plugin/appcenter/helper/appcenter_helper.rb +134 -6
- data/lib/fastlane/plugin/appcenter/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39cd3b20f7c98ea0ac0068fdcdb5e8528b763e747efba88d4c6f8da48f902d6d
|
4
|
+
data.tar.gz: ca7d95d7ed15b4b5aef398dbfc7d83ef318cf7bb976d8551733950b25bf80fec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4f6ae8f7f2b77e0546aa65897362f64959be25b3475c364a85cd3371da31ea3b8b9a8dbc7d77232bdc69172ba34faf61354b5e9b6ea24838e8cab6d14ee418c
|
7
|
+
data.tar.gz: de52913eb094b8592428f60835691873e5ad306b5885de6a1bf7b048cdbfcddc69067cc60806bf1306bee40ed5b9aba5e1d5911fca3315859a024c5a57d924c8
|
data/README.md
CHANGED
@@ -13,47 +13,103 @@ fastlane add_plugin appcenter
|
|
13
13
|
```
|
14
14
|
|
15
15
|
## About App Center
|
16
|
-
With [App Center](https://appcenter.ms) you can continuously build, test, release, and monitor your apps. This plugin provides
|
16
|
+
With [App Center](https://appcenter.ms) you can continuously build, test, release, and monitor your apps. This plugin provides a set of actions to interact with App Center.
|
17
|
+
|
18
|
+
`appcenter_fetch_devices` allows you to obtain the list of iOS devices to distribute an app to (useful for automatic provisioning of testers' devices).
|
19
|
+
|
20
|
+
`appcenter_upload` allows you to upload and [distribute](https://docs.microsoft.com/en-us/appcenter/distribution/uploading) apps to your testers on App Center as well as to upload .dSYM files to [collect detailed crash reports](https://docs.microsoft.com/en-us/appcenter/crashes/ios) in App Center.
|
17
21
|
|
18
22
|
## Usage
|
19
23
|
|
20
24
|
To get started, first, [obtain an API token](https://appcenter.ms/settings/apitokens) in App Center. The API Token is used to authenticate with the App Center API in each call.
|
21
25
|
|
22
26
|
```ruby
|
23
|
-
|
27
|
+
appcenter_fetch_devices(
|
24
28
|
api_token: "<appcenter token>",
|
25
29
|
owner_name: "<appcenter account name of the owner of the app (username or organization URL name)>",
|
26
30
|
app_name: "<appcenter app name>",
|
27
|
-
|
31
|
+
destinations: "*", # Default is 'Collaborators', use '*' for all distribution groups
|
32
|
+
devices_file: "devices.txt" # Default. If you customize, the extension must be .txt
|
33
|
+
)
|
34
|
+
```
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
appcenter_upload(
|
38
|
+
api_token: "<appcenter token>",
|
39
|
+
owner_name: "<appcenter owner name of the app (as seen in app URL)>",
|
40
|
+
app_name: "<appcenter app name (as seen in app URL)>",
|
41
|
+
file: "<path to android build binary>",
|
28
42
|
notify_testers: true # Set to false if you don't want to notify testers of your new release (default: `false`)
|
29
43
|
)
|
30
44
|
```
|
31
45
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
### Help
|
47
|
+
|
48
|
+
Once installed, information and help for an action can be printed out with this command:
|
49
|
+
|
50
|
+
```bash
|
51
|
+
fastlane action appcenter_upload # or any action included with this plugin
|
52
|
+
```
|
53
|
+
|
54
|
+
### A note on App Name
|
55
|
+
|
56
|
+
The `app_name` and `owner_name` as set in the Fastfile come from the app's URL in App Center, in the below form:
|
57
|
+
```
|
58
|
+
https://appcenter.ms/users/{owner_name}/apps/{app_name}
|
59
|
+
```
|
60
|
+
They should not be confused with the displayed name on App Center pages, which is called `app_display_name ` instead.
|
61
|
+
|
62
|
+
### Parameters
|
63
|
+
|
64
|
+
The action parameters `api_token`, `owner_name`, `app_name`, and others can also be omitted when their values are [set as environment variables](https://docs.fastlane.tools/advanced/#environment-variables). By default, `appcenter_upload` will use the same `api_token`, `owner_name`, and `app_name` you used in `appcenter_fetch_devices`.
|
65
|
+
|
66
|
+
Here is the list of all existing parameters:
|
67
|
+
|
68
|
+
#### `appcenter_fetch_devices`
|
69
|
+
|
70
|
+
| Key & Env Var | Description |
|
71
|
+
|-----------------|--------------------|
|
72
|
+
| `api_token` <br/> `APPCENTER_API_TOKEN` | API Token for App Center |
|
73
|
+
| `owner_type` <br/> `APPCENTER_OWNER_TYPE` | Owner type, either 'user' or 'organization' (default: `user`) |
|
74
|
+
| `owner_name` <br/> `APPCENTER_OWNER_NAME` | Owner name, as found in the App's URL in App Center |
|
75
|
+
| `destinations` <br/> `APPCENTER_DISTRIBUTE_DESTINATIONS` | Comma separated list of distribution group names. Default is 'Collaborators', use '*' for all distribution groups |
|
76
|
+
| `devices_file` <br/> `FL_REGISTER_DEVICES_FILE` | File to save the devices list to. Same environment variable as _fastlane_'s `register_devices` action |
|
77
|
+
|
78
|
+
#### `appcenter_upload`
|
79
|
+
|
80
|
+
| Key & Env Var | Description |
|
81
|
+
|-----------------|--------------------|
|
82
|
+
| `api_token` <br/> `APPCENTER_API_TOKEN` | API Token for App Center |
|
83
|
+
| `owner_type` <br/> `APPCENTER_OWNER_TYPE` | Owner type, either 'user' or 'organization' (default: `user`) |
|
84
|
+
| `owner_name` <br/> `APPCENTER_OWNER_NAME` | Owner name, as found in the App's URL in App Center |
|
85
|
+
| `app_name` <br/> `APPCENTER_APP_NAME` | App name as found in the App's URL in App Center, if there is no app with such name, you will be prompted to create one |
|
86
|
+
| `app_display_name` <br/> `APPCENTER_APP_DISPLAY_NAME` | App display name to use when creating a new app |
|
87
|
+
| `app_os` <br/> `APPCENTER_APP_OS` | App OS. Used for new app creation, if app 'app_name' was not found |
|
88
|
+
| `app_platform` <br/> `APPCENTER_APP_PLATFORM` | App Platform. Used for new app creation, if app 'app_name' was not found |
|
89
|
+
| `apk` <br/> `APPCENTER_DISTRIBUTE_APK` | Build release path for android build |
|
90
|
+
| `aab` <br/> `APPCENTER_DISTRIBUTE_AAB` | Build release path for android app bundle build |
|
91
|
+
| `ipa` <br/> `APPCENTER_DISTRIBUTE_IPA` | Build release path for iOS builds |
|
92
|
+
| `file` <br/> `APPCENTER_DISTRIBUTE_FILE` | Build release path for generic builds (.aab, .app, .app.zip, .apk, .dmg, .ipa, .pkg) |
|
93
|
+
| `dsym` <br/> `APPCENTER_DISTRIBUTE_DSYM` | Path to your symbols file. For iOS provide path to app.dSYM.zip |
|
94
|
+
| `upload_dsym_only` <br/> `APPCENTER_DISTRIBUTE_UPLOAD_DSYM_ONLY` | Flag to upload only the dSYM file to App Center (default: `false`) |
|
95
|
+
| `mapping` <br/> `APPCENTER_DISTRIBUTE_ANDROID_MAPPING` | Path to your Android mapping.txt |
|
96
|
+
| `upload_mapping_only` <br/> `APPCENTER_DISTRIBUTE_UPLOAD_ANDROID_MAPPING_ONLY` | Flag to upload only the mapping.txt file to App Center (default: `false`) |
|
97
|
+
| `destinations` <br/> `APPCENTER_DISTRIBUTE_DESTINATIONS` | Comma separated list of destination names. Both distribution groups and stores are supported. All names are required to be of the same destination type (default: `Collaborators`) |
|
98
|
+
| `destination_type` <br/> `APPCENTER_DISTRIBUTE_DESTINATION_TYPE` | Destination type of distribution destination. 'group' and 'store' are supported (default: `group`) |
|
99
|
+
| `mandatory_update` <br/> `APPCENTER_DISTRIBUTE_MANDATORY_UPDATE` | Require users to update to this release. Ignored if destination type is 'store' (default: `false`) |
|
100
|
+
| `notify_testers` <br/> `APPCENTER_DISTRIBUTE_NOTIFY_TESTERS` | Send email notification about release. Ignored if destination type is 'store' (default: `false`) |
|
101
|
+
| `release_notes` <br/> `APPCENTER_DISTRIBUTE_RELEASE_NOTES` | Release notes (default: `No changelog given`) |
|
102
|
+
| `should_clip` <br/> `APPCENTER_DISTRIBUTE_RELEASE_NOTES_CLIPPING` | Clip release notes if its length is more then 5000, true by default (default: `true`) |
|
103
|
+
| `release_notes_link` <br/> `APPCENTER_DISTRIBUTE_RELEASE_NOTES_LINK` | Additional release notes link |
|
104
|
+
| `build_number` <br/> `APPCENTER_DISTRIBUTE_BUILD_NUMBER` | The build number, required for Android ProGuard mapping files, as well as macOS .pkg and .dmg builds |
|
105
|
+
| `version` <br/> `APPCENTER_DISTRIBUTE_VERSION` | The build version, required for Android ProGuard mapping files, as well as macOS .pkg and .dmg builds |
|
106
|
+
| `timeout` <br/> `APPCENTER_DISTRIBUTE_TIMEOUT` | Request timeout in seconds |
|
107
|
+
| `dsa_signature` <br/> `APPCENTER_DISTRIBUTE_DSA_SIGNATURE` | DSA signature of the macOS or Windows releases for Sparkle update feed |
|
108
|
+
|
53
109
|
|
54
110
|
## Example
|
55
111
|
|
56
|
-
Check out
|
112
|
+
Check out this [example `Fastfile`](fastlane/Fastfile) to see how to use the `appcenter_upload` action. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
|
57
113
|
|
58
114
|
Sample uses `.env` for setting private variables like API token, owner name, .etc. You need to replace it in `Fastfile` by your own values.
|
59
115
|
|
@@ -62,6 +118,8 @@ There are three examples in `test` lane:
|
|
62
118
|
- upload release for ios with all set parameters
|
63
119
|
- upload only dSYM file for ios
|
64
120
|
|
121
|
+
Check out this [example `Fastfile`](fastlane/fetch_devices/Fastfile) for a full example of fetching devices, registering them with Apple, provisioning the devices, and signing an app.
|
122
|
+
|
65
123
|
## Run tests for this plugin
|
66
124
|
|
67
125
|
To run both the tests, and code style validation, run
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'csv'
|
3
|
+
require 'faraday'
|
4
|
+
|
5
|
+
module Fastlane
|
6
|
+
module Actions
|
7
|
+
module SharedValues
|
8
|
+
APPCENTER_API_TOKEN = :APPCENTER_API_TOKEN
|
9
|
+
APPCENTER_OWNER_NAME = :APPCENTER_OWNER_NAME
|
10
|
+
APPCENTER_APP_NAME = :APPCENTER_APP_NAME
|
11
|
+
APPCENTER_DISTRIBUTE_DESTINATIONS = :APPCENTER_DISTRIBUTE_DESTINATIONS
|
12
|
+
end
|
13
|
+
|
14
|
+
class AppcenterFetchDevicesAction < Action
|
15
|
+
def self.run(params)
|
16
|
+
api_token = params[:api_token]
|
17
|
+
owner_name = params[:owner_name]
|
18
|
+
app_name = params[:app_name]
|
19
|
+
destinations = params[:destinations]
|
20
|
+
|
21
|
+
Actions.lane_context[SharedValues::APPCENTER_API_TOKEN] = api_token
|
22
|
+
Actions.lane_context[SharedValues::APPCENTER_OWNER_NAME] = owner_name
|
23
|
+
Actions.lane_context[SharedValues::APPCENTER_APP_NAME] = app_name
|
24
|
+
|
25
|
+
group_names = []
|
26
|
+
if destinations == '*'
|
27
|
+
UI.message("Looking up all distribution groups for #{owner_name}/#{app_name}")
|
28
|
+
distribution_groups = Helper::AppcenterHelper.fetch_distribution_groups(
|
29
|
+
api_token: api_token,
|
30
|
+
owner_name: owner_name,
|
31
|
+
app_name: app_name
|
32
|
+
)
|
33
|
+
UI.abort_with_message!("Failed to list distribution groups for #{owner_name}/#{app_name}") unless distribution_groups
|
34
|
+
distribution_groups.each do |group|
|
35
|
+
group_names << group['name']
|
36
|
+
end
|
37
|
+
else
|
38
|
+
group_names += destinations.split(',').map(&:strip)
|
39
|
+
end
|
40
|
+
|
41
|
+
Actions.lane_context[SharedValues::APPCENTER_DISTRIBUTE_DESTINATIONS] = group_names.join(',')
|
42
|
+
|
43
|
+
devices = []
|
44
|
+
group_names.each do |group_name|
|
45
|
+
group_devices = Helper::AppcenterHelper.fetch_devices(
|
46
|
+
api_token: api_token,
|
47
|
+
owner_name: owner_name,
|
48
|
+
app_name: app_name,
|
49
|
+
distribution_group: group_name
|
50
|
+
)
|
51
|
+
UI.abort_with_message!("Failed to get devices for group '#{group_name}'") unless group_devices
|
52
|
+
devices << group_devices
|
53
|
+
end
|
54
|
+
|
55
|
+
self.write_devices(devices: devices, devices_file: params[:devices_file])
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.write_devices(devices:, devices_file:)
|
59
|
+
CSV.open(devices_file, 'w',
|
60
|
+
write_headers: true,
|
61
|
+
headers: ['Device ID', 'Device Name'],
|
62
|
+
col_sep: "\t") do |csv|
|
63
|
+
|
64
|
+
devices.each do |device|
|
65
|
+
CSV.parse(device, { col_sep: "\t", headers: true }) do |row|
|
66
|
+
csv << row
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.description
|
73
|
+
"Fetches a list of devices from App Center to distribute an iOS app to"
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.authors
|
77
|
+
["benkane"]
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.return_value
|
81
|
+
"CSV file formatted for multi-device registration with Apple"
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.details
|
85
|
+
"List is a tab-delimited CSV file containing every device from specified distribution groups for an app in App Center. " +
|
86
|
+
"Especially useful when combined with register_devices and match to automatically register and provision devices with Apple. " +
|
87
|
+
"By default, only the Collaborators group will be included, use `destination: '*'` to match all groups."
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.available_options
|
91
|
+
[
|
92
|
+
FastlaneCore::ConfigItem.new(key: :api_token,
|
93
|
+
env_name: "APPCENTER_API_TOKEN",
|
94
|
+
sensitive: true,
|
95
|
+
description: "API Token for App Center",
|
96
|
+
optional: false,
|
97
|
+
type: String,
|
98
|
+
verify_block: proc do |value|
|
99
|
+
UI.user_error!("No API token for App Center given, pass using `api_token: 'token'`") unless value && !value.empty?
|
100
|
+
end),
|
101
|
+
FastlaneCore::ConfigItem.new(key: :owner_name,
|
102
|
+
env_name: "APPCENTER_OWNER_NAME",
|
103
|
+
description: "Owner name",
|
104
|
+
optional: false,
|
105
|
+
type: String,
|
106
|
+
verify_block: proc do |value|
|
107
|
+
UI.user_error!("No Owner name for App Center given, pass using `owner_name: 'name'`") unless value && !value.empty?
|
108
|
+
end),
|
109
|
+
FastlaneCore::ConfigItem.new(key: :app_name,
|
110
|
+
env_name: "APPCENTER_APP_NAME",
|
111
|
+
description: "App name",
|
112
|
+
optional: false,
|
113
|
+
type: String,
|
114
|
+
verify_block: proc do |value|
|
115
|
+
UI.user_error!("No App name given, pass using `app_name: 'app name'`") unless value && !value.empty?
|
116
|
+
end),
|
117
|
+
FastlaneCore::ConfigItem.new(key: :devices_file,
|
118
|
+
env_name: "FL_REGISTER_DEVICES_FILE",
|
119
|
+
description: "File to save devices to",
|
120
|
+
type: String,
|
121
|
+
default_value: "devices.txt",
|
122
|
+
verify_block: proc do |value|
|
123
|
+
UI.important("Important: Devices file is #{value}. If you plan to upload this file to Apple Developer Center, the file must have the .txt extension") unless value && value.end_with?('.txt')
|
124
|
+
end),
|
125
|
+
FastlaneCore::ConfigItem.new(key: :destinations,
|
126
|
+
env_name: "APPCENTER_DISTRIBUTE_DESTINATIONS",
|
127
|
+
description: "Comma separated list of distribution group names. Default is 'Collaborators', use '*' for all distribution groups",
|
128
|
+
default_value: "Collaborators",
|
129
|
+
type: String)
|
130
|
+
]
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.is_supported?(platform)
|
134
|
+
[:ios].include?(platform)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -94,6 +94,7 @@ module Fastlane
|
|
94
94
|
values = params.values
|
95
95
|
api_token = params[:api_token]
|
96
96
|
owner_name = params[:owner_name]
|
97
|
+
owner_type = params[:owner_type]
|
97
98
|
app_name = params[:app_name]
|
98
99
|
destinations = params[:destinations]
|
99
100
|
destination_type = params[:destination_type]
|
@@ -105,6 +106,7 @@ module Fastlane
|
|
105
106
|
timeout = params[:timeout]
|
106
107
|
build_number = params[:build_number]
|
107
108
|
version = params[:version]
|
109
|
+
dsa_signature = params[:dsa_signature]
|
108
110
|
|
109
111
|
if release_notes.length >= Constants::MAX_RELEASE_NOTES_LENGTH
|
110
112
|
unless should_clip
|
@@ -166,9 +168,11 @@ module Fastlane
|
|
166
168
|
|
167
169
|
if uploaded
|
168
170
|
release_id = uploaded['release_id']
|
169
|
-
|
171
|
+
release_url = Helper::AppcenterHelper.get_release_url(owner_type, owner_name, app_name, release_id)
|
172
|
+
UI.message("Release '#{release_id}' committed: #{release_url}")
|
170
173
|
|
171
174
|
Helper::AppcenterHelper.update_release(api_token, owner_name, app_name, release_id, release_notes)
|
175
|
+
Helper::AppcenterHelper.update_release_metadata(api_token, owner_name, app_name, release_id, dsa_signature)
|
172
176
|
|
173
177
|
destinations_array = destinations.split(',')
|
174
178
|
destinations_array.each do |destination_name|
|
@@ -177,14 +181,17 @@ module Fastlane
|
|
177
181
|
destination_id = destination['id']
|
178
182
|
distributed_release = Helper::AppcenterHelper.add_to_destination(api_token, owner_name, app_name, release_id, destination_type, destination_id, mandatory_update, notify_testers)
|
179
183
|
if distributed_release
|
180
|
-
UI.success("Release #{distributed_release['short_version']} was successfully distributed to #{destination_type} \"#{destination_name}\"")
|
184
|
+
UI.success("Release '#{release_id}' (#{distributed_release['short_version']}) was successfully distributed to #{destination_type} \"#{destination_name}\"")
|
181
185
|
else
|
182
|
-
UI.error("Release '#{release_id}' was not found")
|
186
|
+
UI.error("Release '#{release_id}' was not found for destination '#{destination_name}'")
|
183
187
|
end
|
184
188
|
else
|
185
189
|
UI.error("#{destination_type} '#{destination_name}' was not found")
|
186
190
|
end
|
187
191
|
end
|
192
|
+
|
193
|
+
safe_download_url = Helper::AppcenterHelper.get_install_url(owner_type, owner_name, app_name)
|
194
|
+
UI.message("Release '#{release_id}' is available for download at: #{safe_download_url}")
|
188
195
|
else
|
189
196
|
UI.user_error!("Failed to upload release")
|
190
197
|
end
|
@@ -260,6 +267,7 @@ module Fastlane
|
|
260
267
|
FastlaneCore::ConfigItem.new(key: :api_token,
|
261
268
|
env_name: "APPCENTER_API_TOKEN",
|
262
269
|
description: "API Token for App Center",
|
270
|
+
default_value: Actions.lane_context[SharedValues::APPCENTER_API_TOKEN],
|
263
271
|
optional: false,
|
264
272
|
type: String,
|
265
273
|
verify_block: proc do |value|
|
@@ -268,7 +276,7 @@ module Fastlane
|
|
268
276
|
|
269
277
|
FastlaneCore::ConfigItem.new(key: :owner_type,
|
270
278
|
env_name: "APPCENTER_OWNER_TYPE",
|
271
|
-
description: "Owner type",
|
279
|
+
description: "Owner type, either 'user' or 'organization'",
|
272
280
|
optional: true,
|
273
281
|
default_value: "user",
|
274
282
|
type: String,
|
@@ -279,7 +287,8 @@ module Fastlane
|
|
279
287
|
|
280
288
|
FastlaneCore::ConfigItem.new(key: :owner_name,
|
281
289
|
env_name: "APPCENTER_OWNER_NAME",
|
282
|
-
description: "Owner name",
|
290
|
+
description: "Owner name as found in the App's URL in App Center",
|
291
|
+
default_value: Actions.lane_context[SharedValues::APPCENTER_OWNER_NAME],
|
283
292
|
optional: false,
|
284
293
|
type: String,
|
285
294
|
verify_block: proc do |value|
|
@@ -288,7 +297,8 @@ module Fastlane
|
|
288
297
|
|
289
298
|
FastlaneCore::ConfigItem.new(key: :app_name,
|
290
299
|
env_name: "APPCENTER_APP_NAME",
|
291
|
-
description: "App name. If there is no app with such name, you will be prompted to create one",
|
300
|
+
description: "App name as found in the App's URL in App Center. If there is no app with such name, you will be prompted to create one",
|
301
|
+
default_value: Actions.lane_context[SharedValues::APPCENTER_APP_NAME],
|
292
302
|
optional: false,
|
293
303
|
type: String,
|
294
304
|
verify_block: proc do |value|
|
@@ -303,13 +313,13 @@ module Fastlane
|
|
303
313
|
|
304
314
|
FastlaneCore::ConfigItem.new(key: :app_os,
|
305
315
|
env_name: "APPCENTER_APP_OS",
|
306
|
-
description: "App OS. Used for new app creation, if app
|
316
|
+
description: "App OS. Used for new app creation, if app 'app_name' was not found",
|
307
317
|
optional: true,
|
308
318
|
type: String),
|
309
319
|
|
310
320
|
FastlaneCore::ConfigItem.new(key: :app_platform,
|
311
321
|
env_name: "APPCENTER_APP_PLATFORM",
|
312
|
-
description: "App Platform. Used for new app creation, if app
|
322
|
+
description: "App Platform. Used for new app creation, if app 'app_name' was not found",
|
313
323
|
optional: true,
|
314
324
|
type: String),
|
315
325
|
|
@@ -428,7 +438,7 @@ module Fastlane
|
|
428
438
|
FastlaneCore::ConfigItem.new(key: :destinations,
|
429
439
|
env_name: "APPCENTER_DISTRIBUTE_DESTINATIONS",
|
430
440
|
description: "Comma separated list of destination names. Both distribution groups and stores are supported. All names are required to be of the same destination type",
|
431
|
-
default_value: "Collaborators",
|
441
|
+
default_value: Actions.lane_context[SharedValues::APPCENTER_DISTRIBUTE_DESTINATIONS] || "Collaborators",
|
432
442
|
optional: true,
|
433
443
|
type: String),
|
434
444
|
|
@@ -494,6 +504,12 @@ module Fastlane
|
|
494
504
|
description: "Request timeout in seconds",
|
495
505
|
optional: true,
|
496
506
|
type: Integer),
|
507
|
+
|
508
|
+
FastlaneCore::ConfigItem.new(key: :dsa_signature,
|
509
|
+
env_name: "APPCENTER_DISTRIBUTE_DSA_SIGNATURE",
|
510
|
+
description: "DSA signature of the macOS or Windows releases for Sparkle update feed",
|
511
|
+
optional: true,
|
512
|
+
type: String)
|
497
513
|
]
|
498
514
|
end
|
499
515
|
|
@@ -16,12 +16,12 @@ module Fastlane
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# create request
|
19
|
-
def self.connection(upload_url =
|
19
|
+
def self.connection(upload_url = nil, dsym = false, csv = false)
|
20
20
|
require 'faraday'
|
21
21
|
require 'faraday_middleware'
|
22
22
|
|
23
23
|
options = {
|
24
|
-
url: upload_url
|
24
|
+
url: upload_url || ENV.fetch('APPCENTER_UPLOAD_URL', "https://api.appcenter.ms")
|
25
25
|
}
|
26
26
|
|
27
27
|
Faraday.new(options) do |builder|
|
@@ -31,7 +31,7 @@ module Fastlane
|
|
31
31
|
else
|
32
32
|
builder.request :json
|
33
33
|
end
|
34
|
-
builder.response :json, content_type: /\bjson$/
|
34
|
+
builder.response :json, content_type: /\bjson$/ unless csv
|
35
35
|
builder.use FaradayMiddleware::FollowRedirects
|
36
36
|
builder.adapter :net_http
|
37
37
|
end
|
@@ -151,6 +151,9 @@ module Fastlane
|
|
151
151
|
when 200...300
|
152
152
|
UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
153
153
|
response.body
|
154
|
+
when 401
|
155
|
+
UI.user_error!("Auth Error, provided invalid token")
|
156
|
+
false
|
154
157
|
else
|
155
158
|
UI.error("Error #{response.status}: #{response.body}")
|
156
159
|
false
|
@@ -177,6 +180,9 @@ module Fastlane
|
|
177
180
|
when 200...300
|
178
181
|
self.update_symbol_upload(api_token, owner_name, app_name, symbol_upload_id, 'committed')
|
179
182
|
UI.success("#{logType} uploaded")
|
183
|
+
when 401
|
184
|
+
UI.user_error!("Auth Error, provided invalid token")
|
185
|
+
false
|
180
186
|
else
|
181
187
|
UI.error("Error uploading #{logType} #{response.status}: #{response.body}")
|
182
188
|
self.update_symbol_upload(api_token, owner_name, app_name, symbol_upload_id, 'aborted')
|
@@ -206,6 +212,9 @@ module Fastlane
|
|
206
212
|
when 200...300
|
207
213
|
UI.message("Binary uploaded")
|
208
214
|
self.update_release_upload(api_token, owner_name, app_name, upload_id, 'committed')
|
215
|
+
when 401
|
216
|
+
UI.user_error!("Auth Error, provided invalid token")
|
217
|
+
false
|
209
218
|
else
|
210
219
|
UI.error("Error uploading binary #{response.status}: #{response.body}")
|
211
220
|
self.update_release_upload(api_token, owner_name, app_name, upload_id, 'aborted')
|
@@ -230,6 +239,9 @@ module Fastlane
|
|
230
239
|
when 200...300
|
231
240
|
UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
232
241
|
response.body
|
242
|
+
when 401
|
243
|
+
UI.user_error!("Auth Error, provided invalid token")
|
244
|
+
false
|
233
245
|
when 500...600
|
234
246
|
UI.crash!("Internal Service Error, please try again later")
|
235
247
|
else
|
@@ -254,6 +266,9 @@ module Fastlane
|
|
254
266
|
when 404
|
255
267
|
UI.error("Not found, invalid release url")
|
256
268
|
false
|
269
|
+
when 401
|
270
|
+
UI.user_error!("Auth Error, provided invalid token")
|
271
|
+
false
|
257
272
|
else
|
258
273
|
UI.error("Error fetching information about release #{response.status}: #{response.body}")
|
259
274
|
false
|
@@ -277,6 +292,9 @@ module Fastlane
|
|
277
292
|
when 404
|
278
293
|
UI.error("Not found, invalid distribution #{destination_type} name")
|
279
294
|
false
|
295
|
+
when 401
|
296
|
+
UI.user_error!("Auth Error, provided invalid token")
|
297
|
+
false
|
280
298
|
else
|
281
299
|
UI.error("Error getting #{destination_type} #{response.status}: #{response.body}")
|
282
300
|
false
|
@@ -291,7 +309,7 @@ module Fastlane
|
|
291
309
|
req.headers['X-API-Token'] = api_token
|
292
310
|
req.headers['internal-request-source'] = "fastlane"
|
293
311
|
req.body = {
|
294
|
-
|
312
|
+
release_notes: release_notes
|
295
313
|
}
|
296
314
|
end
|
297
315
|
|
@@ -300,6 +318,7 @@ module Fastlane
|
|
300
318
|
# get full release info
|
301
319
|
release = self.get_release(api_token, owner_name, app_name, release_id)
|
302
320
|
return false unless release
|
321
|
+
|
303
322
|
download_url = release['download_url']
|
304
323
|
|
305
324
|
UI.message("DEBUG: #{JSON.pretty_generate(release)}") if ENV['DEBUG']
|
@@ -307,18 +326,53 @@ module Fastlane
|
|
307
326
|
Actions.lane_context[Fastlane::Actions::SharedValues::APPCENTER_DOWNLOAD_LINK] = download_url
|
308
327
|
Actions.lane_context[Fastlane::Actions::SharedValues::APPCENTER_BUILD_INFORMATION] = release
|
309
328
|
|
310
|
-
UI.message("Release #{release['short_version']} was successfully updated")
|
329
|
+
UI.message("Release '#{release_id}' (#{release['short_version']}) was successfully updated")
|
311
330
|
|
312
331
|
release
|
313
332
|
when 404
|
314
333
|
UI.error("Not found, invalid release id")
|
315
334
|
false
|
335
|
+
when 401
|
336
|
+
UI.user_error!("Auth Error, provided invalid token")
|
337
|
+
false
|
316
338
|
else
|
317
339
|
UI.error("Error adding updating release #{response.status}: #{response.body}")
|
318
340
|
false
|
319
341
|
end
|
320
342
|
end
|
321
343
|
|
344
|
+
# updates release metadata
|
345
|
+
def self.update_release_metadata(api_token, owner_name, app_name, release_id, dsa_signature)
|
346
|
+
return if dsa_signature.to_s == ''
|
347
|
+
|
348
|
+
release_metadata = {
|
349
|
+
dsa_signature: dsa_signature
|
350
|
+
}
|
351
|
+
|
352
|
+
connection = self.connection
|
353
|
+
response = connection.patch("v0.1/apps/#{owner_name}/#{app_name}/releases/#{release_id}") do |req|
|
354
|
+
req.headers['X-API-Token'] = api_token
|
355
|
+
req.headers['internal-request-source'] = "fastlane"
|
356
|
+
req.body = {
|
357
|
+
metadata: release_metadata
|
358
|
+
}
|
359
|
+
end
|
360
|
+
|
361
|
+
case response.status
|
362
|
+
when 200...300
|
363
|
+
UI.message("Release Metadata was successfully updated for release '#{release_id}'")
|
364
|
+
when 404
|
365
|
+
UI.error("Not found, invalid release id")
|
366
|
+
false
|
367
|
+
when 401
|
368
|
+
UI.user_error!("Auth Error, provided invalid token")
|
369
|
+
false
|
370
|
+
else
|
371
|
+
UI.error("Error adding updating release metadata #{response.status}: #{response.body}")
|
372
|
+
false
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
322
376
|
# add release to distribution group or store
|
323
377
|
def self.add_to_destination(api_token, owner_name, app_name, release_id, destination_type, destination_id, mandatory_update = false, notify_testers = false)
|
324
378
|
connection = self.connection
|
@@ -342,6 +396,7 @@ module Fastlane
|
|
342
396
|
# get full release info
|
343
397
|
release = self.get_release(api_token, owner_name, app_name, release_id)
|
344
398
|
return false unless release
|
399
|
+
|
345
400
|
download_url = release['download_url']
|
346
401
|
|
347
402
|
UI.message("DEBUG: received release #{JSON.pretty_generate(release)}") if ENV['DEBUG']
|
@@ -349,12 +404,15 @@ module Fastlane
|
|
349
404
|
Actions.lane_context[Fastlane::Actions::SharedValues::APPCENTER_DOWNLOAD_LINK] = download_url
|
350
405
|
Actions.lane_context[Fastlane::Actions::SharedValues::APPCENTER_BUILD_INFORMATION] = release
|
351
406
|
|
352
|
-
UI.message("
|
407
|
+
UI.message("Release '#{release_id}' (#{release['short_version']}) was successfully distributed'")
|
353
408
|
|
354
409
|
release
|
355
410
|
when 404
|
356
411
|
UI.error("Not found, invalid distribution #{destination_type} name")
|
357
412
|
false
|
413
|
+
when 401
|
414
|
+
UI.user_error!("Auth Error, provided invalid token")
|
415
|
+
false
|
358
416
|
else
|
359
417
|
UI.error("Error adding to #{destination_type} #{response.status}: #{response.body}")
|
360
418
|
false
|
@@ -377,6 +435,9 @@ module Fastlane
|
|
377
435
|
when 404
|
378
436
|
UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
379
437
|
false
|
438
|
+
when 401
|
439
|
+
UI.user_error!("Auth Error, provided invalid token")
|
440
|
+
false
|
380
441
|
else
|
381
442
|
UI.error("Error getting app #{owner_name}/#{app_name}, #{response.status}: #{response.body}")
|
382
443
|
false
|
@@ -406,11 +467,78 @@ module Fastlane
|
|
406
467
|
UI.message("DEBUG: #{JSON.pretty_generate(created)}") if ENV['DEBUG']
|
407
468
|
UI.success("Created #{os}/#{platform} app with name \"#{created['name']}\" and display name \"#{created['display_name']}\" for #{owner_type} \"#{owner_name}\"")
|
408
469
|
true
|
470
|
+
when 401
|
471
|
+
UI.user_error!("Auth Error, provided invalid token")
|
472
|
+
false
|
409
473
|
else
|
410
474
|
UI.error("Error creating app #{response.status}: #{response.body}")
|
411
475
|
false
|
412
476
|
end
|
413
477
|
end
|
478
|
+
|
479
|
+
def self.fetch_distribution_groups(api_token:, owner_name:, app_name:)
|
480
|
+
connection = self.connection
|
481
|
+
|
482
|
+
endpoint = "/v0.1/apps/#{owner_name}/#{app_name}/distribution_groups"
|
483
|
+
|
484
|
+
response = connection.get(endpoint) do |req|
|
485
|
+
req.headers['X-API-Token'] = api_token
|
486
|
+
req.headers['internal-request-source'] = "fastlane"
|
487
|
+
end
|
488
|
+
|
489
|
+
case response.status
|
490
|
+
when 200...300
|
491
|
+
UI.message("DEBUG: #{JSON.pretty_generate(response.body)}\n") if ENV['DEBUG']
|
492
|
+
response.body
|
493
|
+
when 401
|
494
|
+
UI.user_error!("Auth Error, provided invalid token")
|
495
|
+
false
|
496
|
+
when 404
|
497
|
+
UI.error("Not found, invalid owner or application name")
|
498
|
+
false
|
499
|
+
else
|
500
|
+
UI.error("Error #{response.status}: #{response.body}")
|
501
|
+
false
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def self.fetch_devices(api_token:, owner_name:, app_name:, distribution_group:)
|
506
|
+
connection = self.connection(nil, false, true)
|
507
|
+
|
508
|
+
endpoint = "/v0.1/apps/#{owner_name}/#{app_name}/distribution_groups/#{ERB::Util.url_encode(distribution_group)}/devices/download_devices_list"
|
509
|
+
|
510
|
+
response = connection.get(endpoint) do |req|
|
511
|
+
req.headers['X-API-Token'] = api_token
|
512
|
+
req.headers['internal-request-source'] = "fastlane"
|
513
|
+
end
|
514
|
+
|
515
|
+
case response.status
|
516
|
+
when 200...300
|
517
|
+
UI.message("DEBUG: #{response.body.inspect}") if ENV['DEBUG']
|
518
|
+
response.body
|
519
|
+
when 401
|
520
|
+
UI.user_error!("Auth Error, provided invalid token")
|
521
|
+
false
|
522
|
+
when 404
|
523
|
+
UI.error("Not found, invalid owner, application or distribution group name")
|
524
|
+
false
|
525
|
+
else
|
526
|
+
UI.error("Error #{response.status}: #{response.body}")
|
527
|
+
false
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
# Note: This does not support testing environment (INT)
|
532
|
+
def self.get_release_url(owner_type, owner_name, app_name, release_id)
|
533
|
+
owner_path = owner_type == "user" ? "users/#{owner_name}" : "orgs/#{owner_name}"
|
534
|
+
return "https://appcenter.ms/#{owner_path}/apps/#{app_name}/distribute/releases/#{release_id}"
|
535
|
+
end
|
536
|
+
|
537
|
+
# Note: This does not support testing environment (INT)
|
538
|
+
def self.get_install_url(owner_type, owner_name, app_name)
|
539
|
+
owner_path = owner_type == "user" ? "users/#{owner_name}" : "orgs/#{owner_name}"
|
540
|
+
return "https://install.appcenter.ms/#{owner_path}/apps/#{app_name}"
|
541
|
+
end
|
414
542
|
end
|
415
543
|
end
|
416
544
|
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: 1.
|
4
|
+
version: 1.5.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: 2019-
|
11
|
+
date: 2019-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- LICENSE
|
104
104
|
- README.md
|
105
105
|
- lib/fastlane/plugin/appcenter.rb
|
106
|
+
- lib/fastlane/plugin/appcenter/actions/appcenter_fetch_devices_action.rb
|
106
107
|
- lib/fastlane/plugin/appcenter/actions/appcenter_upload_action.rb
|
107
108
|
- lib/fastlane/plugin/appcenter/helper/appcenter_helper.rb
|
108
109
|
- lib/fastlane/plugin/appcenter/version.rb
|