fastlane-plugin-sapfire 1.1.0 → 1.2.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 +6 -2
- data/lib/fastlane/plugin/sapfire/actions/associate_ms_store_action.rb +104 -74
- data/lib/fastlane/plugin/sapfire/actions/ms_credentials_action.rb +7 -10
- data/lib/fastlane/plugin/sapfire/actions/upload_ms_store_action.rb +40 -7
- data/lib/fastlane/plugin/sapfire/helper/ms_credentials.rb +47 -0
- data/lib/fastlane/plugin/sapfire/helper/ms_devcenter_helper.rb +117 -62
- data/lib/fastlane/plugin/sapfire/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: 88044ddcaf677c20f2d9e0b7b2a54e1f92b2b609344815c82ff3d26b2344385f
|
4
|
+
data.tar.gz: 1e060c84cc0da8e87ee0f01aa8e3030745310c6cc97f89ef451a3f760371e615
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c751b85ff40459a46faee5598277794d05e5da1d679e12b4fbb8b261a893824f58bd04ef77acb4b5251288993669414bf4e0ad5ceb276cc76f65901576809f38
|
7
|
+
data.tar.gz: 2cccb183366378b8987a2f709078409bc967ca2831ef34bd4e2ac56a5214c690b94a32d39d54acfdcf250b8d6207a381206208cb055c38359121727663054f03
|
data/README.md
CHANGED
@@ -34,9 +34,13 @@ but also can be used independently via command-line interface.
|
|
34
34
|
**Microsoft Store** is a digital distribution platform for Windows.
|
35
35
|
|
36
36
|
## Getting started
|
37
|
-
To get started working with plugin, add it to your
|
37
|
+
To get started working with plugin, add it to your project by running:
|
38
|
+
```shell
|
39
|
+
fastlane add_plugin sapfire
|
40
|
+
```
|
41
|
+
Or, if you want to pick the latest commit from the repository, add this to `fastlane/Pluginfile`:
|
38
42
|
```ruby
|
39
|
-
gem "fastlane-plugin-sapfire", git: "https://github.com/fastlane/fastlane-plugin-sapfire"
|
43
|
+
gem "fastlane-plugin-sapfire", git: "https://github.com/fastlane/fastlane-plugin-sapfire.git"
|
40
44
|
```
|
41
45
|
|
42
46
|
## Usage
|
@@ -2,10 +2,15 @@ require "uri"
|
|
2
2
|
require "net/http"
|
3
3
|
require "json"
|
4
4
|
require "fastlane/action"
|
5
|
+
require_relative "../helper/ms_credentials"
|
5
6
|
|
6
7
|
module Fastlane
|
7
8
|
module Actions
|
8
9
|
class AssociateMsStoreAction < Action
|
10
|
+
@token = ""
|
11
|
+
@vsapi_host = ""
|
12
|
+
@vsapi_endpoint = ""
|
13
|
+
|
9
14
|
XML_NAME = "Package.StoreAssociation.xml".freeze
|
10
15
|
|
11
16
|
def self.run(params)
|
@@ -14,10 +19,11 @@ module Fastlane
|
|
14
19
|
begin
|
15
20
|
UI.message("Creating #{XML_NAME}...")
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
22
|
+
acquire_authorization_token
|
23
|
+
acquire_vsapi_location
|
24
|
+
ms_developer_info = developer_info
|
25
|
+
ms_app_info = app_info(params[:app_id])
|
26
|
+
create_xml(params[:manifest], ms_developer_info, ms_app_info)
|
21
27
|
|
22
28
|
UI.message("#{XML_NAME} successfully created")
|
23
29
|
rescue StandardError => ex
|
@@ -26,50 +32,46 @@ module Fastlane
|
|
26
32
|
end
|
27
33
|
|
28
34
|
def self.create_xml(manifest_path, developer_info, app_info)
|
29
|
-
app_identity = app_info[:identity]
|
30
|
-
app_names = app_info[:names]
|
31
|
-
publisher = developer_info[:publisher]
|
32
|
-
publisher_display_name = developer_info[:display_name]
|
33
35
|
appxmanifest_xml = get_appxmanifest_xml(manifest_path)
|
34
36
|
|
35
|
-
UI.message("Set identity name: #{
|
37
|
+
UI.message("Set identity name: #{app_info.identity}")
|
36
38
|
|
37
39
|
begin
|
38
40
|
identity_entry = appxmanifest_xml.elements["Package"]
|
39
41
|
.elements["Identity"]
|
40
|
-
identity_entry.attributes["Name"] =
|
41
|
-
identity_entry.attributes["Publisher"] = publisher
|
42
|
+
identity_entry.attributes["Name"] = app_info.identity
|
43
|
+
identity_entry.attributes["Publisher"] = developer_info.publisher
|
42
44
|
|
43
45
|
properties_entry = appxmanifest_xml.elements["Package"]
|
44
46
|
.elements["Properties"]
|
45
|
-
properties_entry.elements["DisplayName"].text =
|
46
|
-
properties_entry.elements["PublisherDisplayName"].text =
|
47
|
+
properties_entry.elements["DisplayName"].text = app_info.names[0] unless app_info.names.empty?
|
48
|
+
properties_entry.elements["PublisherDisplayName"].text = developer_info.display_name
|
47
49
|
rescue StandardError => ex
|
48
50
|
UI.user_error!("Can't update app manifest: #{ex}")
|
49
51
|
end
|
50
52
|
|
51
53
|
save_xml(appxmanifest_xml, manifest_path)
|
52
54
|
|
53
|
-
UI.message("Set publisher data: #{publisher}")
|
54
|
-
UI.message("Set publisher display name: #{
|
55
|
+
UI.message("Set publisher data: #{developer_info.publisher}")
|
56
|
+
UI.message("Set publisher display name: #{developer_info.display_name}")
|
55
57
|
|
56
58
|
document = REXML::Document.new
|
57
59
|
document.xml_decl.version = "1.0"
|
58
60
|
document.xml_decl.encoding = "utf-8"
|
59
|
-
|
60
|
-
store_association = document.add_element("StoreAssociation", {
|
61
|
+
xmlns_args = {
|
61
62
|
"xmlns" => "http://schemas.microsoft.com/appx/2010/storeassociation"
|
62
|
-
}
|
63
|
-
store_association.add_element("
|
64
|
-
store_association.add_element("
|
63
|
+
}
|
64
|
+
store_association = document.add_element("StoreAssociation", xmlns_args)
|
65
|
+
store_association.add_element("Publisher").text = developer_info.publisher
|
66
|
+
store_association.add_element("PublisherDisplayName").text = developer_info.display_name
|
65
67
|
store_association.add_element("DeveloperAccountType").text = "WSA"
|
66
68
|
store_association.add_element("GeneratePackageHash").text = "http://www.w3.org/2001/04/xmlenc#sha256"
|
67
69
|
|
68
70
|
product_reserved_info = store_association.add_element("ProductReservedInfo")
|
69
|
-
product_reserved_info.add_element("MainPackageIdentityName").text =
|
71
|
+
product_reserved_info.add_element("MainPackageIdentityName").text = app_info.identity
|
70
72
|
|
71
73
|
reserved_names = product_reserved_info.add_element("ReservedNames")
|
72
|
-
|
74
|
+
app_info.names.each do |x|
|
73
75
|
reserved_names.add_element("ReservedName").text = x
|
74
76
|
end
|
75
77
|
|
@@ -96,72 +98,61 @@ module Fastlane
|
|
96
98
|
file.close
|
97
99
|
end
|
98
100
|
|
99
|
-
def self.
|
101
|
+
def self.developer_info
|
100
102
|
UI.message("Obtaining developer info ...")
|
101
103
|
|
102
104
|
headers = {
|
103
|
-
"Authorization": "Bearer #{token}",
|
105
|
+
"Authorization": "Bearer #{@token}",
|
104
106
|
"Accept": "application/json",
|
105
107
|
"MS-Contract-Version": "1"
|
106
108
|
}
|
107
109
|
query = {
|
108
110
|
setvar: "fltaad:1"
|
109
111
|
}
|
110
|
-
|
111
|
-
uri = URI("https://developer.microsoft.com/vsapi/developer")
|
112
|
-
uri.query = URI.encode_www_form(query)
|
113
|
-
https = Net::HTTP.new(uri.host, uri.port)
|
114
|
-
https.use_ssl = true
|
115
|
-
request = Net::HTTP::Get.new(uri, headers)
|
116
|
-
response = https.request(request)
|
112
|
+
connection = Faraday.new(@vsapi_host)
|
117
113
|
|
118
114
|
begin
|
119
|
-
|
115
|
+
response = connection.get("#{@vsapi_endpoint}/developer", query, headers)
|
116
|
+
|
117
|
+
if response.status == 200
|
118
|
+
data = JSON.parse(response.body)
|
119
|
+
developer_info = DeveloperInfo.new(data["PublisherDisplayName"], data["Publisher"])
|
120
120
|
|
121
|
-
if response.code == "200"
|
122
121
|
UI.message("Developer info was obtained")
|
123
|
-
|
124
|
-
|
125
|
-
publisher: data["Publisher"]
|
126
|
-
}
|
122
|
+
|
123
|
+
return developer_info
|
127
124
|
end
|
128
125
|
|
129
|
-
UI.user_error!("Request returned the error: #{response.
|
126
|
+
UI.user_error!("Request returned the error: #{response.status}")
|
130
127
|
rescue StandardError => ex
|
131
128
|
UI.user_error!("Developer info request failed: #{ex}")
|
132
129
|
end
|
133
130
|
end
|
134
131
|
|
135
|
-
def self.
|
132
|
+
def self.app_info(app_id)
|
136
133
|
UI.message("Obtaining application info ...")
|
137
134
|
|
138
135
|
headers = {
|
139
|
-
"Authorization": "Bearer #{token}",
|
136
|
+
"Authorization": "Bearer #{@token}",
|
140
137
|
"Accept": "application/json",
|
141
138
|
"MS-Contract-Version": "1"
|
142
139
|
}
|
143
140
|
query = {
|
144
141
|
setvar: "fltaad:1"
|
145
142
|
}
|
146
|
-
|
147
|
-
uri = URI("https://developer.microsoft.com/vsapi/applications")
|
148
|
-
uri.query = URI.encode_www_form(query)
|
149
|
-
https = Net::HTTP.new(uri.host, uri.port)
|
150
|
-
https.use_ssl = true
|
151
|
-
request = Net::HTTP::Get.new(uri, headers)
|
152
|
-
response = https.request(request)
|
143
|
+
connection = Faraday.new(@vsapi_host)
|
153
144
|
|
154
145
|
begin
|
155
|
-
|
146
|
+
response = connection.get("#{@vsapi_endpoint}/applications", query, headers)
|
147
|
+
|
148
|
+
if response.status == 200
|
149
|
+
data = JSON.parse(response.body)
|
150
|
+
product = data["Products"].find { |x| x["LandingUrl"].include?(app_id) }
|
151
|
+
app_info = AppInfo.new(product["MainPackageIdentityName"], product["ReservedNames"])
|
156
152
|
|
157
|
-
if response.code == "200"
|
158
153
|
UI.message("Application info was obtained")
|
159
154
|
|
160
|
-
|
161
|
-
return {
|
162
|
-
identity: product["MainPackageIdentityName"],
|
163
|
-
names: product["ReservedNames"]
|
164
|
-
}
|
155
|
+
return app_info
|
165
156
|
end
|
166
157
|
|
167
158
|
UI.user_error!("Request returned the error: #{response.code}")
|
@@ -173,40 +164,33 @@ module Fastlane
|
|
173
164
|
def self.acquire_authorization_token
|
174
165
|
UI.message("Acquiring authorization token ...")
|
175
166
|
|
176
|
-
|
177
|
-
password = Actions.lane_context[SharedValues::SF_MS_PASSWORD]
|
178
|
-
tenant_id = Actions.lane_context[SharedValues::SF_MS_TENANT_ID]
|
179
|
-
client_id = Actions.lane_context[SharedValues::SF_MS_CLIENT_ID]
|
180
|
-
client_secret = Actions.lane_context[SharedValues::SF_MS_CLIENT_SECRET]
|
181
|
-
|
167
|
+
ms_credentials = Helper.ms_credentials
|
182
168
|
body = {
|
183
|
-
client_id: client_id,
|
184
|
-
client_secret: client_secret,
|
169
|
+
client_id: ms_credentials.client_id,
|
170
|
+
client_secret: ms_credentials.client_secret,
|
185
171
|
client_info: 1,
|
186
172
|
grant_type: "password",
|
187
|
-
scope: "https://
|
188
|
-
username: username,
|
189
|
-
password: password
|
173
|
+
scope: "https://graph.windows.net/.default offline_access openid profile",
|
174
|
+
username: ms_credentials.username,
|
175
|
+
password: ms_credentials.password
|
190
176
|
}
|
191
177
|
headers = {
|
192
|
-
"x-anchormailbox": "upn:#{username}",
|
178
|
+
"x-anchormailbox": "upn:#{ms_credentials.username}",
|
193
179
|
"x-client-sku": "fastlane-sapfire-plugin",
|
194
180
|
"Accept": "application/json"
|
195
181
|
}
|
196
|
-
|
197
|
-
uri = URI("https://login.microsoftonline.com/#{tenant_id}/oauth2/v2.0/token")
|
198
|
-
https = Net::HTTP.new(uri.host, uri.port)
|
199
|
-
https.use_ssl = true
|
200
|
-
request = Net::HTTP::Post.new(uri, headers)
|
182
|
+
connection = Faraday.new("https://login.microsoftonline.com")
|
201
183
|
request_body = URI.encode_www_form(body)
|
202
|
-
response = https.request(request, request_body)
|
203
184
|
|
204
185
|
begin
|
186
|
+
response = connection.post("/#{ms_credentials.tenant_id}/oauth2/v2.0/token", request_body, headers)
|
205
187
|
data = JSON.parse(response.body)
|
206
188
|
|
207
|
-
if response.
|
189
|
+
if response.status == 200
|
190
|
+
@token = data["access_token"]
|
208
191
|
UI.message("Authorization token was obtained")
|
209
|
-
|
192
|
+
|
193
|
+
return
|
210
194
|
end
|
211
195
|
|
212
196
|
error = data["error"]
|
@@ -218,6 +202,34 @@ module Fastlane
|
|
218
202
|
end
|
219
203
|
end
|
220
204
|
|
205
|
+
def self.acquire_vsapi_location
|
206
|
+
query = {
|
207
|
+
LinkId: "875315" # VS API constant
|
208
|
+
}
|
209
|
+
connection = Faraday.new("https://go.microsoft.com")
|
210
|
+
|
211
|
+
begin
|
212
|
+
response = connection.get("/fwlink", query)
|
213
|
+
|
214
|
+
if response.status == 302
|
215
|
+
raise "'Location' header isn't presented" unless response.headers.include?("Location")
|
216
|
+
|
217
|
+
location = response.headers["Location"]
|
218
|
+
uri = URI(location)
|
219
|
+
@vsapi_host = "#{uri.scheme}://#{uri.host}"
|
220
|
+
@vsapi_endpoint = uri.path
|
221
|
+
|
222
|
+
UI.message("VS API endpoint: #{location}")
|
223
|
+
|
224
|
+
return
|
225
|
+
end
|
226
|
+
|
227
|
+
UI.user_error!("Request returned the error: #{response.status}")
|
228
|
+
rescue StandardError => ex
|
229
|
+
UI.user_error!("Failed to get VS API endpoint location: #{ex}")
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
221
233
|
def self.description
|
222
234
|
"Makes a local app manifest needed for Microsoft Store association"
|
223
235
|
end
|
@@ -268,5 +280,23 @@ module Fastlane
|
|
268
280
|
:project
|
269
281
|
end
|
270
282
|
end
|
283
|
+
|
284
|
+
class DeveloperInfo
|
285
|
+
attr_reader :display_name, :publisher
|
286
|
+
|
287
|
+
def initialize(display_name, publisher)
|
288
|
+
@display_name = display_name
|
289
|
+
@publisher = publisher
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
class AppInfo
|
294
|
+
attr_reader :identity, :names
|
295
|
+
|
296
|
+
def initialize(identity, names)
|
297
|
+
@identity = identity
|
298
|
+
@names = names
|
299
|
+
end
|
300
|
+
end
|
271
301
|
end
|
272
302
|
end
|
@@ -1,22 +1,19 @@
|
|
1
1
|
require "fastlane/action"
|
2
|
+
require_relative "../helper/ms_credentials"
|
2
3
|
|
3
4
|
module Fastlane
|
4
5
|
module Actions
|
5
6
|
module SharedValues
|
6
|
-
|
7
|
-
SF_MS_PASSWORD = :SF_MS_PASSWORD
|
8
|
-
SF_MS_TENANT_ID = :SF_MS_TENANT_ID
|
9
|
-
SF_MS_CLIENT_ID = :SF_MS_CLIENT_ID
|
10
|
-
SF_MS_CLIENT_SECRET = :SF_MS_CLIENT_SECRET
|
7
|
+
SF_MS_CREDENTIALS = :SF_MS_CREDENTIALS
|
11
8
|
end
|
12
9
|
|
13
10
|
class MsCredentialsAction < Action
|
14
11
|
def self.run(params)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
Helper.ms_credentials.username = params[:username]
|
13
|
+
Helper.ms_credentials.password = params[:password]
|
14
|
+
Helper.ms_credentials.tenant_id = params[:tenant_id]
|
15
|
+
Helper.ms_credentials.client_id = params[:client_id]
|
16
|
+
Helper.ms_credentials.client_secret = params[:client_secret]
|
20
17
|
|
21
18
|
UI.success("Credentials for Azure AD account is successfully saved for further actions")
|
22
19
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "fastlane/action"
|
2
|
+
require_relative "../helper/ms_credentials"
|
2
3
|
require_relative "../helper/ms_devcenter_helper"
|
3
4
|
require_relative "../msbuild/options"
|
4
5
|
|
@@ -8,18 +9,37 @@ module Fastlane
|
|
8
9
|
DEFAULT_TIMEOUT = 300
|
9
10
|
|
10
11
|
def self.run(params)
|
11
|
-
|
12
|
-
client_id = Actions.lane_context[SharedValues::SF_MS_CLIENT_ID]
|
13
|
-
client_secret = Actions.lane_context[SharedValues::SF_MS_CLIENT_SECRET]
|
12
|
+
ms_credentials = Helper.ms_credentials
|
14
13
|
app_id = params[:app_id]
|
15
14
|
path = params[:path]
|
16
15
|
timeout = params.values.include?(:timeout) && params[:timeout].positive? ? params[:timeout] : DEFAULT_TIMEOUT
|
17
16
|
|
18
17
|
UI.message("Acquiring authorization token for DevCenter ...")
|
19
|
-
auth_token = Helper::MsDevCenterHelper.acquire_authorization_token(tenant_id,
|
18
|
+
auth_token = Helper::MsDevCenterHelper.acquire_authorization_token(ms_credentials.tenant_id,
|
19
|
+
ms_credentials.client_id,
|
20
|
+
ms_credentials.client_secret,
|
21
|
+
timeout)
|
20
22
|
UI.message("Authorization token was obtained")
|
21
23
|
|
22
24
|
UI.message("Creating submission for app #{app_id} ...")
|
25
|
+
pending_submission = Helper::MsDevCenterHelper.non_published_submission(app_id, auth_token, timeout)
|
26
|
+
submission_id = pending_submission["id"]
|
27
|
+
|
28
|
+
unless pending_submission.nil?
|
29
|
+
if params.values.include?(:remove_pending_submission) &&
|
30
|
+
[true].include?(params[:remove_pending_submission])
|
31
|
+
UI.message("Pending submission #{submission_id} were found and scheduled for deletion due to 'remove_pending_submission' argument set to 'true'")
|
32
|
+
Helper::MsDevCenterHelper.remove_submission(app_id, submission_id, auth_token, timeout)
|
33
|
+
UI.message("Pending submission deleted")
|
34
|
+
else
|
35
|
+
UI.user_error!([
|
36
|
+
"There is a pending submission #{submission_id} has already been created.",
|
37
|
+
"You need to either proceed it or remove before creating a new one.",
|
38
|
+
"Set 'remove_pending_submission' argument to 'true' to do that automatically."
|
39
|
+
].join(" "))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
23
43
|
submission_obj = Helper::MsDevCenterHelper.create_submission(app_id, auth_token, timeout)
|
24
44
|
submission_id = submission_obj["id"]
|
25
45
|
UI.message("Submission #{submission_id} created")
|
@@ -46,7 +66,6 @@ module Fastlane
|
|
46
66
|
[true].include?(params[:skip_waiting_for_build_processing])
|
47
67
|
UI.success("Submission passed, but build processing were skipped. Check the Dev Center page.")
|
48
68
|
return
|
49
|
-
|
50
69
|
end
|
51
70
|
|
52
71
|
status = false
|
@@ -127,6 +146,13 @@ module Fastlane
|
|
127
146
|
default_value: false,
|
128
147
|
type: Fastlane::Boolean
|
129
148
|
),
|
149
|
+
FastlaneCore::ConfigItem.new(
|
150
|
+
key: :remove_pending_submission,
|
151
|
+
description: "If set to true, the pending submission halts - a new one will be created automatically",
|
152
|
+
optional: true,
|
153
|
+
default_value: false,
|
154
|
+
type: Fastlane::Boolean
|
155
|
+
),
|
130
156
|
FastlaneCore::ConfigItem.new(
|
131
157
|
key: :path,
|
132
158
|
env_name: "SF_PACKAGE",
|
@@ -156,8 +182,8 @@ module Fastlane
|
|
156
182
|
end
|
157
183
|
|
158
184
|
def self.create_blob_zip(package_path)
|
159
|
-
File.delete(File.join(File.dirname(package_path), "blob.zip"))
|
160
185
|
zip_path = File.join(File.dirname(package_path), "blob.zip")
|
186
|
+
File.delete(zip_path) if File.exist?(zip_path)
|
161
187
|
|
162
188
|
Zip::File.open(zip_path, create: true) do |file|
|
163
189
|
file.add(File.basename(package_path), package_path)
|
@@ -181,7 +207,14 @@ module Fastlane
|
|
181
207
|
"minimumSystemRam": "None"
|
182
208
|
}
|
183
209
|
|
184
|
-
|
210
|
+
if submission_obj[key].empty?
|
211
|
+
submission_obj[key] = []
|
212
|
+
else
|
213
|
+
submission_obj[key].each do |existing_package|
|
214
|
+
existing_package["fileStatus"] = "PendingDelete"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
185
218
|
submission_obj[key].append(package)
|
186
219
|
submission_obj
|
187
220
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Helper
|
3
|
+
class MsCredentials
|
4
|
+
attr_writer :username, :password, :tenant_id, :client_id, :client_secret
|
5
|
+
|
6
|
+
def username
|
7
|
+
check_value("username", @username)
|
8
|
+
@username
|
9
|
+
end
|
10
|
+
|
11
|
+
def password
|
12
|
+
check_value("password", @password)
|
13
|
+
@password
|
14
|
+
end
|
15
|
+
|
16
|
+
def tenant_id
|
17
|
+
check_value("tenant_id", @tenant_id)
|
18
|
+
@tenant_id
|
19
|
+
end
|
20
|
+
|
21
|
+
def client_id
|
22
|
+
check_value("client_id", @client_id)
|
23
|
+
@client_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def client_secret
|
27
|
+
check_value("client_secret", @client_secret)
|
28
|
+
@client_secret
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_value(name, value)
|
32
|
+
raise "Microsoft credential variable hasn't been set: #{name}. You must call ms_credentials action before." if
|
33
|
+
value.nil? || value.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
private(:check_value)
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
attr_accessor :ms_credentials
|
41
|
+
end
|
42
|
+
|
43
|
+
self.ms_credentials = MsCredentials.new
|
44
|
+
|
45
|
+
private_class_method(:ms_credentials=)
|
46
|
+
end
|
47
|
+
end
|
@@ -53,19 +53,24 @@ module Fastlane
|
|
53
53
|
url_data = parse_upload_url(url)
|
54
54
|
url_data[:query]["comp"] = "block"
|
55
55
|
url_data[:query]["blockid"] = id
|
56
|
-
|
57
56
|
connection = Faraday.new(url_data[:host])
|
58
|
-
response = connection.put(url_data[:path]) do |req|
|
59
|
-
req.headers = headers
|
60
|
-
req.params = url_data[:query]
|
61
|
-
req.body = bytes
|
62
|
-
req.options.timeout = timeout if timeout.positive?
|
63
|
-
end
|
64
57
|
|
65
|
-
|
58
|
+
begin
|
59
|
+
response = connection.put(url_data[:path]) do |req|
|
60
|
+
req.headers = headers
|
61
|
+
req.params = url_data[:query]
|
62
|
+
req.body = bytes
|
63
|
+
req.options.timeout = timeout if timeout.positive?
|
64
|
+
end
|
65
|
+
|
66
|
+
return true if response.status == 201
|
67
|
+
|
68
|
+
error = response.body.to_s
|
69
|
+
UI.error("Upload request failed.\nCode: #{response.status}\nError: #{error}")
|
70
|
+
rescue StandardError => ex
|
71
|
+
UI.error("Upload request failed: #{ex}")
|
72
|
+
end
|
66
73
|
|
67
|
-
error = response.body.to_s
|
68
|
-
UI.error("Upload request failed.\nCode: #{response.status}\nError: #{error}")
|
69
74
|
false
|
70
75
|
end
|
71
76
|
|
@@ -81,18 +86,23 @@ module Fastlane
|
|
81
86
|
|
82
87
|
url_data = parse_upload_url(url)
|
83
88
|
url_data[:query]["comp"] = "blocklist"
|
84
|
-
|
85
89
|
connection = Faraday.new(url_data[:host])
|
86
|
-
response = connection.put(url_data[:path]) do |req|
|
87
|
-
req.params = url_data[:query]
|
88
|
-
req.body = document.to_s
|
89
|
-
req.options.timeout = timeout if timeout.positive?
|
90
|
-
end
|
91
90
|
|
92
|
-
|
91
|
+
begin
|
92
|
+
response = connection.put(url_data[:path]) do |req|
|
93
|
+
req.params = url_data[:query]
|
94
|
+
req.body = document.to_s
|
95
|
+
req.options.timeout = timeout if timeout.positive?
|
96
|
+
end
|
97
|
+
|
98
|
+
return true if response.status == 201
|
99
|
+
|
100
|
+
error = response.body.to_s
|
101
|
+
UI.error("Upload block list request failed.\nCode: #{response.status}\nError: #{error}")
|
102
|
+
rescue StandardError => ex
|
103
|
+
UI.error("Upload block list request failed: #{ex}")
|
104
|
+
end
|
93
105
|
|
94
|
-
error = response.body.to_s
|
95
|
-
UI.error("Upload block list request failed.\nCode: #{response.status}\nError: #{error}")
|
96
106
|
false
|
97
107
|
end
|
98
108
|
|
@@ -100,16 +110,17 @@ module Fastlane
|
|
100
110
|
check_app_id(app_id)
|
101
111
|
|
102
112
|
connection = Faraday.new(HOST)
|
103
|
-
response = connection.get("/#{API_VERSION}/#{API_ROOT}/#{app_id}") do |req|
|
104
|
-
req.headers = build_headers(auth_token)
|
105
|
-
req.options.timeout = timeout if timeout.positive?
|
106
|
-
end
|
107
113
|
|
108
114
|
begin
|
115
|
+
response = connection.get("/#{API_VERSION}/#{API_ROOT}/#{app_id}") do |req|
|
116
|
+
req.headers = build_headers(auth_token)
|
117
|
+
req.options.timeout = timeout if timeout.positive?
|
118
|
+
end
|
109
119
|
data = JSON.parse(response.body)
|
120
|
+
|
110
121
|
return data if response.status == 200
|
111
122
|
|
112
|
-
UI.user_error!("
|
123
|
+
UI.user_error!("Getting app request returned the error.\nCode: #{response.status}")
|
113
124
|
rescue StandardError => ex
|
114
125
|
UI.user_error!("Getting app info process failed: #{ex}")
|
115
126
|
end
|
@@ -117,27 +128,22 @@ module Fastlane
|
|
117
128
|
|
118
129
|
def self.create_submission(app_id, auth_token, timeout = 0)
|
119
130
|
check_app_id(app_id)
|
120
|
-
if non_published_submission?(app_id, auth_token, timeout)
|
121
|
-
UI.user_error!([
|
122
|
-
"There is a pending submission has already been created.",
|
123
|
-
"You need to either proceed it or remove before creating a new one."
|
124
|
-
].join(" "))
|
125
|
-
end
|
126
131
|
|
127
132
|
connection = Faraday.new(HOST)
|
128
|
-
response = connection.post("/#{API_VERSION}/#{API_ROOT}/#{app_id}/submissions") do |req|
|
129
|
-
req.headers = build_headers(auth_token)
|
130
|
-
req.options.timeout = timeout if timeout.positive?
|
131
|
-
end
|
132
133
|
|
133
134
|
begin
|
135
|
+
response = connection.post("/#{API_VERSION}/#{API_ROOT}/#{app_id}/submissions") do |req|
|
136
|
+
req.headers = build_headers(auth_token)
|
137
|
+
req.options.timeout = timeout if timeout.positive?
|
138
|
+
end
|
134
139
|
data = JSON.parse(response.body)
|
140
|
+
|
135
141
|
return data if response.status == 201
|
136
142
|
|
137
143
|
code = data["code"]
|
138
144
|
message = data["message"]
|
139
145
|
|
140
|
-
UI.user_error!("
|
146
|
+
UI.user_error!("Creating submission request returned the error.\nCode: #{response.status} #{code}.\nDescription: #{message}")
|
141
147
|
rescue StandardError => ex
|
142
148
|
UI.user_error!("Creating submission process failed: #{ex}")
|
143
149
|
end
|
@@ -149,17 +155,18 @@ module Fastlane
|
|
149
155
|
|
150
156
|
submission_id = submission_obj["id"]
|
151
157
|
connection = Faraday.new(HOST)
|
152
|
-
response = connection.put("/#{API_VERSION}/#{API_ROOT}/#{app_id}/submissions/#{submission_id}") do |req|
|
153
|
-
req.headers = build_headers(auth_token)
|
154
|
-
req.body = submission_obj.to_json
|
155
|
-
req.options.timeout = timeout if timeout.positive?
|
156
|
-
end
|
157
158
|
|
158
159
|
begin
|
160
|
+
response = connection.put("/#{API_VERSION}/#{API_ROOT}/#{app_id}/submissions/#{submission_id}") do |req|
|
161
|
+
req.headers = build_headers(auth_token)
|
162
|
+
req.body = submission_obj.to_json
|
163
|
+
req.options.timeout = timeout if timeout.positive?
|
164
|
+
end
|
159
165
|
data = JSON.parse(response.body)
|
166
|
+
|
160
167
|
return data if response.status == 200
|
161
168
|
|
162
|
-
UI.user_error!("
|
169
|
+
UI.user_error!("Updating submission request returned the error.\nCode: #{response.status}")
|
163
170
|
rescue StandardError => ex
|
164
171
|
UI.user_error!("Updating submission process failed: #{ex}")
|
165
172
|
end
|
@@ -170,29 +177,75 @@ module Fastlane
|
|
170
177
|
check_submission_id(submission_id)
|
171
178
|
|
172
179
|
connection = Faraday.new(HOST)
|
173
|
-
|
174
|
-
|
175
|
-
|
180
|
+
|
181
|
+
begin
|
182
|
+
response = connection.post("/#{API_VERSION}/#{API_ROOT}/#{app_id}/submissions/#{submission_id}/commit") do |req|
|
183
|
+
req.headers = build_headers(auth_token)
|
184
|
+
req.options.timeout = timeout if timeout.positive?
|
185
|
+
end
|
186
|
+
|
187
|
+
UI.user_error!("Committing submission request returned the error.\nCode: #{response.status}") unless response.status == 202
|
188
|
+
rescue StandardError => ex
|
189
|
+
UI.user_error!("Committing submission process failed: #{ex}")
|
176
190
|
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.remove_submission(app_id, submission_id, auth_token, timeout = 0)
|
194
|
+
check_app_id(app_id)
|
195
|
+
check_submission_id(submission_id)
|
196
|
+
|
197
|
+
connection = Faraday.new(HOST)
|
177
198
|
|
178
|
-
|
199
|
+
begin
|
200
|
+
response = connection.delete("/#{API_VERSION}/#{API_ROOT}/#{app_id}/submissions/#{submission_id}") do |req|
|
201
|
+
req.headers = build_headers(auth_token)
|
202
|
+
req.options.timeout = timeout if timeout.positive?
|
203
|
+
end
|
204
|
+
|
205
|
+
UI.user_error!("Deleting submission request returned the error.\nCode: #{response.status}") unless response.status == 204
|
206
|
+
rescue StandardError => ex
|
207
|
+
UI.user_error!("Deleting submission process failed: #{ex}")
|
208
|
+
end
|
179
209
|
end
|
180
210
|
|
181
211
|
def self.get_submission_status(app_id, submission_id, auth_token, timeout = 0)
|
182
212
|
check_app_id(app_id)
|
183
213
|
check_submission_id(submission_id)
|
184
214
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
215
|
+
response = get_submission_status_internal(app_id, submission_id, auth_token, timeout)
|
216
|
+
|
217
|
+
# Sometimes MS can return internal server error code (500) that is not directly related to uploading process.
|
218
|
+
# Once it happens, retry 3 times until we'll get a success response.
|
219
|
+
if response[:status] == 500
|
220
|
+
server_error_500_retry_counter = 0
|
221
|
+
|
222
|
+
until server_error_500_retry_counter < 2
|
223
|
+
server_error_500_retry_counter += 1
|
224
|
+
response = get_submission_status_internal(app_id, submission_id, auth_token, timeout)
|
225
|
+
break if response.nil? || response[:status] == 200
|
226
|
+
end
|
189
227
|
end
|
190
228
|
|
229
|
+
return response[:data] if !response.nil? && response[:status] == 200
|
230
|
+
|
231
|
+
UI.user_error!("Submission status obtaining request returned the error.\nCode: #{response[:status]}")
|
232
|
+
end
|
233
|
+
|
234
|
+
def self.get_submission_status_internal(app_id, submission_id, auth_token, timeout = 0)
|
235
|
+
connection = Faraday.new(HOST)
|
236
|
+
|
191
237
|
begin
|
192
|
-
|
193
|
-
|
238
|
+
response = connection.get("/#{API_VERSION}/#{API_ROOT}/#{app_id}/submissions/#{submission_id}/status") do |req|
|
239
|
+
req.headers = build_headers(auth_token)
|
240
|
+
req.options.timeout = timeout if timeout.positive?
|
241
|
+
end
|
194
242
|
|
195
|
-
UI.
|
243
|
+
UI.error("Submission status obtaining request returned the error.\nCode: #{response.status}") if response.status != 200
|
244
|
+
data = response.status == 200 ? JSON.parse(response.body) : nil
|
245
|
+
{
|
246
|
+
"data": data,
|
247
|
+
"status": response.status
|
248
|
+
}
|
196
249
|
rescue StandardError => ex
|
197
250
|
UI.user_error!("Submission status obtaining process failed: #{ex}")
|
198
251
|
end
|
@@ -208,31 +261,31 @@ module Fastlane
|
|
208
261
|
headers = {
|
209
262
|
"Content-Type": "application/x-www-form-urlencoded"
|
210
263
|
}.merge(REQUEST_HEADERS)
|
211
|
-
|
212
264
|
connection = Faraday.new("https://login.microsoftonline.com")
|
213
|
-
response = connection.post("/#{tenant_id}/oauth2/token") do |req|
|
214
|
-
req.headers = headers
|
215
|
-
req.body = body
|
216
|
-
req.options.timeout = timeout if timeout.positive?
|
217
|
-
end
|
218
265
|
|
219
266
|
begin
|
267
|
+
response = connection.post("/#{tenant_id}/oauth2/token") do |req|
|
268
|
+
req.headers = headers
|
269
|
+
req.body = body
|
270
|
+
req.options.timeout = timeout if timeout.positive?
|
271
|
+
end
|
220
272
|
data = JSON.parse(response.body)
|
273
|
+
|
221
274
|
return data["access_token"] if response.status == 200
|
222
275
|
|
223
276
|
error = data["error"]
|
224
277
|
error_description = data["error_description"]
|
225
278
|
|
226
|
-
UI.user_error!("
|
279
|
+
UI.user_error!("Authorization request returned the error.\nCode: #{error}.\nDescription: #{error_description}")
|
227
280
|
rescue StandardError => ex
|
228
281
|
UI.user_error!("Authorization failed: #{ex}")
|
229
282
|
end
|
230
283
|
end
|
231
284
|
|
232
|
-
def self.non_published_submission
|
285
|
+
def self.non_published_submission(app_id, auth_token, timeout = 0)
|
233
286
|
check_app_id(app_id)
|
234
287
|
app_info = get_app_info(app_id, auth_token, timeout)
|
235
|
-
app_info
|
288
|
+
app_info["pendingApplicationSubmission"]
|
236
289
|
end
|
237
290
|
|
238
291
|
def self.build_headers(auth_token)
|
@@ -270,16 +323,18 @@ module Fastlane
|
|
270
323
|
public_class_method(:create_submission)
|
271
324
|
public_class_method(:update_submission)
|
272
325
|
public_class_method(:commit_submission)
|
326
|
+
public_class_method(:remove_submission)
|
273
327
|
public_class_method(:get_submission_status)
|
274
328
|
public_class_method(:acquire_authorization_token)
|
329
|
+
public_class_method(:non_published_submission)
|
275
330
|
|
276
331
|
private_class_method(:upload_block)
|
277
332
|
private_class_method(:upload_block_list)
|
278
|
-
private_class_method(:non_published_submission?)
|
279
333
|
private_class_method(:build_headers)
|
280
334
|
private_class_method(:parse_upload_url)
|
281
335
|
private_class_method(:check_app_id)
|
282
336
|
private_class_method(:check_submission_id)
|
337
|
+
private_class_method(:get_submission_status_internal)
|
283
338
|
|
284
339
|
private_constant(:HOST)
|
285
340
|
private_constant(:API_VERSION)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-sapfire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- CheeryLee
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -145,6 +145,7 @@ files:
|
|
145
145
|
- lib/fastlane/plugin/sapfire/actions/upload_ms_store_action.rb
|
146
146
|
- lib/fastlane/plugin/sapfire/actions/upload_nuget_action.rb
|
147
147
|
- lib/fastlane/plugin/sapfire/actions_base/msbuild_action_base.rb
|
148
|
+
- lib/fastlane/plugin/sapfire/helper/ms_credentials.rb
|
148
149
|
- lib/fastlane/plugin/sapfire/helper/ms_devcenter_helper.rb
|
149
150
|
- lib/fastlane/plugin/sapfire/helper/sapfire_helper.rb
|
150
151
|
- lib/fastlane/plugin/sapfire/msbuild/module.rb
|