fastlane-plugin-appcircle_testing_distribution 0.4.3.beta.2 → 0.5.0.beta.1
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 +18 -0
- data/lib/fastlane/plugin/appcircle_testing_distribution/actions/appcircle_testing_distribution_action.rb +35 -16
- data/lib/fastlane/plugin/appcircle_testing_distribution/helper/TDAuthService.rb +6 -6
- data/lib/fastlane/plugin/appcircle_testing_distribution/helper/TDUploadService.rb +62 -26
- data/lib/fastlane/plugin/appcircle_testing_distribution/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 83c9d8655326e41c07f7b6d927fb63441c01059e2c29c2658338931c5a2ae718
|
|
4
|
+
data.tar.gz: fc194ce33b458182af4725f5e21b525666c9cab85cc41b9c5a2d29444251488d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a0568378f254b846f291bc6dc9bb0b149b8590f8945fa521f91d670eca5bca37818af392cf9028cc3580ff6bb92ad6cb07a5c606e016b7a0da07fac215bf1a4
|
|
7
|
+
data.tar.gz: 4a64eab748b2a2163b464ac87793982687940e8c9df4cb1ca8ca7501f42e7d91472b91c66eb627b0fa07fb7bb2b8bb7f77bae07608bb6b866d04737f7defda10
|
data/README.md
CHANGED
|
@@ -104,6 +104,24 @@ Provide **either** `personalAPIToken` **or** `personalAccessKey` — not both. I
|
|
|
104
104
|
- `appPath`: Indicates the file path to the application package that will be uploaded to Appcircle Testing Distribution Profile.
|
|
105
105
|
- `message`: Your message to testers, ensuring they receive important updates and information regarding the application.
|
|
106
106
|
|
|
107
|
+
### Self-Hosted Appcircle
|
|
108
|
+
|
|
109
|
+
If you run a self-hosted Appcircle installation, point the plugin to your own endpoints. Both parameters are optional and default to the Appcircle cloud, so existing cloud users do not need to set them.
|
|
110
|
+
|
|
111
|
+
- `authEndpoint` (optional): Authentication endpoint URL. Defaults to `https://auth.appcircle.io`.
|
|
112
|
+
- `apiEndpoint` (optional): API endpoint URL. Defaults to `https://api.appcircle.io`.
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
appcircle_testing_distribution(
|
|
116
|
+
personalAPIToken: ENV["AC_PERSONAL_API_TOKEN"],
|
|
117
|
+
authEndpoint: "https://auth.my-appcircle.example.com",
|
|
118
|
+
apiEndpoint: "https://api.my-appcircle.example.com",
|
|
119
|
+
profileName: ENV["AC_PROFILE_NAME"],
|
|
120
|
+
appPath: ENV["AC_APP_PATH"],
|
|
121
|
+
message: ENV["AC_MESSAGE"]
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
107
125
|
## Further Details
|
|
108
126
|
|
|
109
127
|
For more information please refer to the documentation.
|
|
@@ -33,6 +33,9 @@ module Fastlane
|
|
|
33
33
|
#
|
|
34
34
|
appPath = params[:appPath]
|
|
35
35
|
message = params[:message]
|
|
36
|
+
#
|
|
37
|
+
authEndpoint = params[:authEndpoint]
|
|
38
|
+
apiEndpoint = params[:apiEndpoint]
|
|
36
39
|
|
|
37
40
|
profileAuthType = AUTH_TYPE_MAPPING[profileAuthType] # map input to API values
|
|
38
41
|
|
|
@@ -46,23 +49,25 @@ module Fastlane
|
|
|
46
49
|
# Auth
|
|
47
50
|
authToken = self.ac_login(personal_api_token: personalAPIToken,
|
|
48
51
|
personal_access_key: personalAccessKey,
|
|
49
|
-
sub_organization_name: subOrganizationName
|
|
52
|
+
sub_organization_name: subOrganizationName,
|
|
53
|
+
auth_endpoint: authEndpoint,
|
|
54
|
+
api_endpoint: apiEndpoint)
|
|
50
55
|
|
|
51
56
|
# Get or create profile
|
|
52
|
-
profileId = self.ac_get_or_create_profile(authToken, profileName, createProfileIfNotExists, profileCreationSettings, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames)
|
|
57
|
+
profileId = self.ac_get_or_create_profile(authToken, profileName, createProfileIfNotExists, profileCreationSettings, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames, apiEndpoint)
|
|
53
58
|
|
|
54
59
|
# Upload package
|
|
55
|
-
self.ac_upload(authToken, appPath, profileId, profileName, message)
|
|
60
|
+
self.ac_upload(authToken, appPath, profileId, profileName, message, apiEndpoint)
|
|
56
61
|
end
|
|
57
62
|
|
|
58
|
-
def self.ac_login(personal_api_token:, personal_access_key:, sub_organization_name:)
|
|
63
|
+
def self.ac_login(personal_api_token:, personal_access_key:, sub_organization_name:, auth_endpoint:, api_endpoint:)
|
|
59
64
|
begin
|
|
60
65
|
token = ''
|
|
61
66
|
|
|
62
67
|
if personal_access_key
|
|
63
|
-
user = TDAuthService.get_ac_token_with_personal_access_key(personal_access_key: personal_access_key)
|
|
68
|
+
user = TDAuthService.get_ac_token_with_personal_access_key(personal_access_key: personal_access_key, auth_endpoint: auth_endpoint)
|
|
64
69
|
else
|
|
65
|
-
user = TDAuthService.get_ac_token(pat: personal_api_token)
|
|
70
|
+
user = TDAuthService.get_ac_token(pat: personal_api_token, auth_endpoint: auth_endpoint)
|
|
66
71
|
end
|
|
67
72
|
UI.success("Login is successful.")
|
|
68
73
|
token = user.accessToken
|
|
@@ -71,8 +76,8 @@ module Fastlane
|
|
|
71
76
|
if personal_access_key
|
|
72
77
|
UI.important("Warning: subOrganizationName is currently only supported with personalAPIToken auth. Ignoring sub-organization switch for Personal Access Key login.")
|
|
73
78
|
else
|
|
74
|
-
organization_id = TDAuthService.get_organization_id(access_token: token, name: sub_organization_name)
|
|
75
|
-
user = TDAuthService.get_ac_token(pat: personal_api_token, sub_organization_id: organization_id)
|
|
79
|
+
organization_id = TDAuthService.get_organization_id(access_token: token, name: sub_organization_name, api_endpoint: api_endpoint)
|
|
80
|
+
user = TDAuthService.get_ac_token(pat: personal_api_token, sub_organization_id: organization_id, auth_endpoint: auth_endpoint)
|
|
76
81
|
UI.message("Switched to sub-organization: #{sub_organization_name}")
|
|
77
82
|
token = user.accessToken
|
|
78
83
|
end
|
|
@@ -85,9 +90,9 @@ module Fastlane
|
|
|
85
90
|
end
|
|
86
91
|
end
|
|
87
92
|
|
|
88
|
-
def self.ac_get_or_create_profile(authToken, profileName, createProfileIfNotExists, profileCreationSettings, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames)
|
|
93
|
+
def self.ac_get_or_create_profile(authToken, profileName, createProfileIfNotExists, profileCreationSettings, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames, apiEndpoint)
|
|
89
94
|
begin
|
|
90
|
-
profileId = TDUploadService.get_profile_id(authToken, profileName)
|
|
95
|
+
profileId = TDUploadService.get_profile_id(authToken, profileName, apiEndpoint)
|
|
91
96
|
|
|
92
97
|
if profileId
|
|
93
98
|
UI.message("Profile '#{profileName}' found with ID: #{profileId}.")
|
|
@@ -97,7 +102,7 @@ module Fastlane
|
|
|
97
102
|
UI.user_error!("Error: Profile '#{profileName}' not found. The option 'createProfileIfNotExists' is set to false, so a new profile was not created. To automatically create a new profile when it doesn't exist, set 'createProfileIfNotExists' to true.")
|
|
98
103
|
elsif profileId.nil? && createProfileIfNotExists
|
|
99
104
|
UI.message("Profile '#{profileName}' not found. Creating the new profile...")
|
|
100
|
-
profileId = TDUploadService.create_profile(authToken, profileName, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames)
|
|
105
|
+
profileId = TDUploadService.create_profile(authToken, profileName, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames, apiEndpoint)
|
|
101
106
|
end
|
|
102
107
|
|
|
103
108
|
return profileId
|
|
@@ -107,11 +112,11 @@ module Fastlane
|
|
|
107
112
|
end
|
|
108
113
|
end
|
|
109
114
|
|
|
110
|
-
def self.ac_upload(token, appPath, profileID, profileName, message)
|
|
115
|
+
def self.ac_upload(token, appPath, profileID, profileName, message, apiEndpoint)
|
|
111
116
|
begin
|
|
112
117
|
UI.message("Upload started.")
|
|
113
|
-
response = TDUploadService.upload_artifact(token: token, message: message, app: appPath, dist_profile_id: profileID)
|
|
114
|
-
result = self.checkTaskStatus(token, response['taskId'])
|
|
118
|
+
response = TDUploadService.upload_artifact(token: token, message: message, app: appPath, dist_profile_id: profileID, api_endpoint: apiEndpoint)
|
|
119
|
+
result = self.checkTaskStatus(token, response['taskId'], apiEndpoint)
|
|
115
120
|
|
|
116
121
|
if result
|
|
117
122
|
UI.success("#{appPath} uploaded to profile '#{profileName}' successfully 🎉")
|
|
@@ -122,8 +127,8 @@ module Fastlane
|
|
|
122
127
|
end
|
|
123
128
|
end
|
|
124
129
|
|
|
125
|
-
def self.checkTaskStatus(authToken, taskId)
|
|
126
|
-
uri = URI.parse("
|
|
130
|
+
def self.checkTaskStatus(authToken, taskId, apiEndpoint)
|
|
131
|
+
uri = URI.parse("#{apiEndpoint}/task/v1/tasks/#{taskId}")
|
|
127
132
|
|
|
128
133
|
check_interval = 1
|
|
129
134
|
# timeout = 2 * 60 * 60 # 2 hours in seconds
|
|
@@ -197,6 +202,20 @@ module Fastlane
|
|
|
197
202
|
optional: true,
|
|
198
203
|
type: String),
|
|
199
204
|
|
|
205
|
+
FastlaneCore::ConfigItem.new(key: :authEndpoint,
|
|
206
|
+
env_name: "AC_AUTH_ENDPOINT",
|
|
207
|
+
description: "Optional: Authentication endpoint URL for self-hosted Appcircle installations. Defaults to the Appcircle cloud",
|
|
208
|
+
optional: true,
|
|
209
|
+
default_value: "https://auth.appcircle.io",
|
|
210
|
+
type: String),
|
|
211
|
+
|
|
212
|
+
FastlaneCore::ConfigItem.new(key: :apiEndpoint,
|
|
213
|
+
env_name: "AC_API_ENDPOINT",
|
|
214
|
+
description: "Optional: API endpoint URL for self-hosted Appcircle installations. Defaults to the Appcircle cloud",
|
|
215
|
+
optional: true,
|
|
216
|
+
default_value: "https://api.appcircle.io",
|
|
217
|
+
type: String),
|
|
218
|
+
|
|
200
219
|
FastlaneCore::ConfigItem.new(key: :profileName,
|
|
201
220
|
env_name: "AC_PROFILE_NAME",
|
|
202
221
|
description: "Enter the profile name of the Appcircle testing distribution profile. This name uniquely identifies the profile under which your applications will be distributed",
|
|
@@ -13,8 +13,8 @@ class UserResponse
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
module TDAuthService
|
|
16
|
-
def self.get_ac_token(pat:, sub_organization_id: nil)
|
|
17
|
-
endpoint_url =
|
|
16
|
+
def self.get_ac_token(pat:, sub_organization_id: nil, auth_endpoint: 'https://auth.appcircle.io')
|
|
17
|
+
endpoint_url = "#{auth_endpoint}/auth/v2/token"
|
|
18
18
|
uri = URI(endpoint_url)
|
|
19
19
|
|
|
20
20
|
# Create HTTP request
|
|
@@ -46,8 +46,8 @@ module TDAuthService
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def self.get_organization_id(access_token:, name:)
|
|
50
|
-
endpoint_url =
|
|
49
|
+
def self.get_organization_id(access_token:, name:, api_endpoint: 'https://api.appcircle.io')
|
|
50
|
+
endpoint_url = "#{api_endpoint}/identity/v1/organizations"
|
|
51
51
|
uri = URI(endpoint_url)
|
|
52
52
|
|
|
53
53
|
# Create HTTP request
|
|
@@ -74,8 +74,8 @@ module TDAuthService
|
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
def self.get_ac_token_with_personal_access_key(personal_access_key:)
|
|
78
|
-
endpoint_url =
|
|
77
|
+
def self.get_ac_token_with_personal_access_key(personal_access_key:, auth_endpoint: 'https://auth.appcircle.io')
|
|
78
|
+
endpoint_url = "#{auth_endpoint}/auth/v1/token"
|
|
79
79
|
uri = URI(endpoint_url)
|
|
80
80
|
|
|
81
81
|
# Create HTTP request
|
|
@@ -8,12 +8,35 @@ BASE_URL = "https://api.appcircle.io"
|
|
|
8
8
|
module TDUploadService
|
|
9
9
|
UI = FastlaneCore::UI
|
|
10
10
|
|
|
11
|
-
def self.
|
|
11
|
+
def self.put_with_retry(url, body, headers, max_retries: 5)
|
|
12
|
+
attempt = 0
|
|
13
|
+
delay = 1.0
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
RestClient.put(url, body, headers)
|
|
17
|
+
rescue => e
|
|
18
|
+
status = e.respond_to?(:http_code) ? e.http_code : nil
|
|
19
|
+
retryable = status == 503 ||
|
|
20
|
+
e.is_a?(RestClient::ServerBrokeConnection) ||
|
|
21
|
+
e.is_a?(Errno::ECONNRESET) ||
|
|
22
|
+
(defined?(RestClient::Exceptions::OpenTimeout) && e.is_a?(RestClient::Exceptions::OpenTimeout)) ||
|
|
23
|
+
(defined?(RestClient::Exceptions::ReadTimeout) && e.is_a?(RestClient::Exceptions::ReadTimeout))
|
|
24
|
+
|
|
25
|
+
raise e if !retryable || attempt >= max_retries
|
|
26
|
+
|
|
27
|
+
attempt += 1
|
|
28
|
+
sleep(delay + rand(0.3))
|
|
29
|
+
delay *= 2
|
|
30
|
+
retry
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.upload_artifact(token:, message:, app:, dist_profile_id:, api_endpoint: BASE_URL)
|
|
12
35
|
file_path = app
|
|
13
36
|
file_name = File.basename(file_path)
|
|
14
37
|
file_size = File.size(file_path)
|
|
15
38
|
|
|
16
|
-
upload_info_url = "#{
|
|
39
|
+
upload_info_url = "#{api_endpoint}/distribution/v1/profiles/#{dist_profile_id}/app-versions"
|
|
17
40
|
headers = {
|
|
18
41
|
Authorization: "Bearer #{token}",
|
|
19
42
|
accept: 'application/json'
|
|
@@ -38,14 +61,25 @@ module TDUploadService
|
|
|
38
61
|
end
|
|
39
62
|
file_id = upload_info['fileId']
|
|
40
63
|
upload_url = upload_info['uploadUrl']
|
|
64
|
+
configuration = upload_info['configuration']
|
|
65
|
+
http_method = (configuration && configuration['httpMethod']) ? configuration['httpMethod'].to_s.upcase : 'PUT'
|
|
41
66
|
|
|
42
|
-
file_content = File.binread(file_path)
|
|
43
67
|
UI.message("Uploading file to Appcircle...")
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
|
|
68
|
+
if http_method == 'POST'
|
|
69
|
+
sign_parameters = configuration['signParameters'] || {}
|
|
70
|
+
payload = {}
|
|
71
|
+
sign_parameters.each { |key, value| payload[key] = value }
|
|
72
|
+
payload['file'] = File.new(file_path, 'rb')
|
|
73
|
+
response = RestClient.post(upload_url, payload)
|
|
74
|
+
else
|
|
75
|
+
file_content = File.binread(file_path)
|
|
76
|
+
response = put_with_retry(
|
|
77
|
+
upload_url,
|
|
78
|
+
file_content,
|
|
79
|
+
{ content_type: 'application/octet-stream' }
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
49
83
|
if response.code.between?(200, 299)
|
|
50
84
|
UI.success("File upload finished successfully with status code: #{response.code}")
|
|
51
85
|
else
|
|
@@ -53,7 +87,7 @@ module TDUploadService
|
|
|
53
87
|
raise "File upload failed."
|
|
54
88
|
end
|
|
55
89
|
|
|
56
|
-
commit_url = "#{
|
|
90
|
+
commit_url = "#{api_endpoint}/distribution/v1/profiles/#{dist_profile_id}/app-versions"
|
|
57
91
|
uri = URI(commit_url)
|
|
58
92
|
uri.query = URI.encode_www_form({ action: 'commitFileUpload' })
|
|
59
93
|
|
|
@@ -87,8 +121,8 @@ module TDUploadService
|
|
|
87
121
|
end
|
|
88
122
|
end
|
|
89
123
|
|
|
90
|
-
def self.get_distribution_profiles(auth_token:)
|
|
91
|
-
url = "#{
|
|
124
|
+
def self.get_distribution_profiles(auth_token:, api_endpoint: BASE_URL)
|
|
125
|
+
url = "#{api_endpoint}/distribution/v2/profiles"
|
|
92
126
|
|
|
93
127
|
# Set up the headers with authentication
|
|
94
128
|
headers = {
|
|
@@ -106,8 +140,8 @@ module TDUploadService
|
|
|
106
140
|
end
|
|
107
141
|
end
|
|
108
142
|
|
|
109
|
-
def self.get_testing_groups(auth_token:)
|
|
110
|
-
url = "#{
|
|
143
|
+
def self.get_testing_groups(auth_token:, api_endpoint: BASE_URL)
|
|
144
|
+
url = "#{api_endpoint}/distribution/v2/testing-groups"
|
|
111
145
|
|
|
112
146
|
# Set up the headers with authentication
|
|
113
147
|
headers = {
|
|
@@ -125,8 +159,8 @@ module TDUploadService
|
|
|
125
159
|
end
|
|
126
160
|
end
|
|
127
161
|
|
|
128
|
-
def self.create_distribution_profile(name:, auth_token:)
|
|
129
|
-
url = "#{
|
|
162
|
+
def self.create_distribution_profile(name:, auth_token:, api_endpoint: BASE_URL)
|
|
163
|
+
url = "#{api_endpoint}/distribution/v2/profiles"
|
|
130
164
|
headers = {
|
|
131
165
|
Authorization: "Bearer #{auth_token}",
|
|
132
166
|
content_type: :json,
|
|
@@ -146,8 +180,8 @@ module TDUploadService
|
|
|
146
180
|
end
|
|
147
181
|
end
|
|
148
182
|
|
|
149
|
-
def self.update_distribution_profile(profile_id:, auth_type:, username:, password:, testing_group_ids:, auth_token:)
|
|
150
|
-
url = "#{
|
|
183
|
+
def self.update_distribution_profile(profile_id:, auth_type:, username:, password:, testing_group_ids:, auth_token:, api_endpoint: BASE_URL)
|
|
184
|
+
url = "#{api_endpoint}/distribution/v2/profiles/#{profile_id}"
|
|
151
185
|
headers = {
|
|
152
186
|
Authorization: "Bearer #{auth_token}",
|
|
153
187
|
content_type: :json,
|
|
@@ -179,11 +213,11 @@ module TDUploadService
|
|
|
179
213
|
end
|
|
180
214
|
end
|
|
181
215
|
|
|
182
|
-
def self.get_profile_id(authToken, profileName)
|
|
216
|
+
def self.get_profile_id(authToken, profileName, api_endpoint = BASE_URL)
|
|
183
217
|
profileId = nil
|
|
184
218
|
|
|
185
219
|
begin
|
|
186
|
-
profiles = TDUploadService.get_distribution_profiles(auth_token: authToken)
|
|
220
|
+
profiles = TDUploadService.get_distribution_profiles(auth_token: authToken, api_endpoint: api_endpoint)
|
|
187
221
|
profiles.each do |profile|
|
|
188
222
|
if profile["name"] == profileName
|
|
189
223
|
profileId = profile['id']
|
|
@@ -197,12 +231,12 @@ module TDUploadService
|
|
|
197
231
|
return profileId
|
|
198
232
|
end
|
|
199
233
|
|
|
200
|
-
def self.get_testing_group_ids(authToken, testingGroupNames)
|
|
234
|
+
def self.get_testing_group_ids(authToken, testingGroupNames, api_endpoint = BASE_URL)
|
|
201
235
|
testingGroupIds = []
|
|
202
236
|
remainingGroupNames = Set.new(testingGroupNames)
|
|
203
237
|
|
|
204
238
|
begin
|
|
205
|
-
groups = TDUploadService.get_testing_groups(auth_token: authToken)
|
|
239
|
+
groups = TDUploadService.get_testing_groups(auth_token: authToken, api_endpoint: api_endpoint)
|
|
206
240
|
|
|
207
241
|
groups.each do |group|
|
|
208
242
|
if remainingGroupNames.include?(group["name"])
|
|
@@ -219,17 +253,18 @@ module TDUploadService
|
|
|
219
253
|
return testingGroupIds
|
|
220
254
|
end
|
|
221
255
|
|
|
222
|
-
def self.create_profile(authToken, profileName, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames)
|
|
256
|
+
def self.create_profile(authToken, profileName, profileAuthType, profileUsername, profilePassword, profileTestingGroupNames, api_endpoint = BASE_URL)
|
|
223
257
|
# Get testing group IDs
|
|
224
258
|
if !profileTestingGroupNames&.empty?
|
|
225
|
-
profileTestingGroupIds = TDUploadService.get_testing_group_ids(authToken, profileTestingGroupNames)
|
|
259
|
+
profileTestingGroupIds = TDUploadService.get_testing_group_ids(authToken, profileTestingGroupNames, api_endpoint)
|
|
226
260
|
end
|
|
227
|
-
|
|
261
|
+
|
|
228
262
|
# Create
|
|
229
263
|
begin
|
|
230
264
|
new_profile = TDUploadService.create_distribution_profile(
|
|
231
265
|
name: profileName,
|
|
232
|
-
auth_token: authToken
|
|
266
|
+
auth_token: authToken,
|
|
267
|
+
api_endpoint: api_endpoint
|
|
233
268
|
)
|
|
234
269
|
if new_profile.nil?
|
|
235
270
|
raise "Error: The new profile could not be created."
|
|
@@ -248,7 +283,8 @@ module TDUploadService
|
|
|
248
283
|
username: profileUsername,
|
|
249
284
|
password: profilePassword,
|
|
250
285
|
testing_group_ids: profileTestingGroupIds,
|
|
251
|
-
auth_token: authToken
|
|
286
|
+
auth_token: authToken,
|
|
287
|
+
api_endpoint: api_endpoint
|
|
252
288
|
)
|
|
253
289
|
if configured_profile.nil?
|
|
254
290
|
raise "Error: The new profile could not be configured."
|