fastlane-plugin-sapfire 1.0.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.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +135 -0
  4. data/lib/fastlane/plugin/sapfire/actions/app_certification_action.rb +79 -0
  5. data/lib/fastlane/plugin/sapfire/actions/associate_ms_store_action.rb +263 -0
  6. data/lib/fastlane/plugin/sapfire/actions/build_uwp_app_action.rb +55 -0
  7. data/lib/fastlane/plugin/sapfire/actions/dotnet_select_action.rb +46 -0
  8. data/lib/fastlane/plugin/sapfire/actions/ensure_dotnet_version_action.rb +123 -0
  9. data/lib/fastlane/plugin/sapfire/actions/ms_credentials_action.rb +91 -0
  10. data/lib/fastlane/plugin/sapfire/actions/msbuild_action.rb +45 -0
  11. data/lib/fastlane/plugin/sapfire/actions/msbuild_select_action.rb +53 -0
  12. data/lib/fastlane/plugin/sapfire/actions/nuget_pack_action.rb +46 -0
  13. data/lib/fastlane/plugin/sapfire/actions/update_uwp_signing_settings_action.rb +73 -0
  14. data/lib/fastlane/plugin/sapfire/actions/upload_ms_store_action.rb +218 -0
  15. data/lib/fastlane/plugin/sapfire/actions/upload_nuget_action.rb +95 -0
  16. data/lib/fastlane/plugin/sapfire/actions_base/msbuild_action_base.rb +42 -0
  17. data/lib/fastlane/plugin/sapfire/helper/ms_devcenter_helper.rb +292 -0
  18. data/lib/fastlane/plugin/sapfire/helper/sapfire_helper.rb +55 -0
  19. data/lib/fastlane/plugin/sapfire/msbuild/module.rb +34 -0
  20. data/lib/fastlane/plugin/sapfire/msbuild/options.rb +123 -0
  21. data/lib/fastlane/plugin/sapfire/msbuild/runner.rb +171 -0
  22. data/lib/fastlane/plugin/sapfire/sln_project/block.rb +30 -0
  23. data/lib/fastlane/plugin/sapfire/sln_project/global_block.rb +147 -0
  24. data/lib/fastlane/plugin/sapfire/sln_project/module.rb +14 -0
  25. data/lib/fastlane/plugin/sapfire/sln_project/project_block.rb +82 -0
  26. data/lib/fastlane/plugin/sapfire/sln_project/root_block.rb +72 -0
  27. data/lib/fastlane/plugin/sapfire/version.rb +5 -0
  28. data/lib/fastlane/plugin/sapfire.rb +16 -0
  29. metadata +182 -0
@@ -0,0 +1,123 @@
1
+ require "open3"
2
+ require_relative "../helper/sapfire_helper"
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class EnsureDotnetVersionAction < Action
7
+ def self.run(params)
8
+ UI.user_error!("Can't find dotnet") unless Helper::SapfireHelper.dotnet_specified?
9
+
10
+ dotnet_path = Actions.lane_context[SharedValues::SF_DOTNET_PATH]
11
+ cmd = "\"#{dotnet_path}\" --list-sdks"
12
+
13
+ UI.command(cmd)
14
+ stdin, stdout = Open3.popen2(cmd)
15
+ output = stdout.read
16
+ stdin.close
17
+ stdout.close
18
+
19
+ versions = output.split("\n")
20
+ available_versions = []
21
+ current_version = nil
22
+ required_version = nil
23
+ found = false
24
+
25
+ begin
26
+ required_version = Gem::Version.new(params[:version])
27
+ rescue ArgumentError => ex
28
+ UI.user_error!("Invalid version number provided, make sure it's valid: #{ex}")
29
+ end
30
+
31
+ required_version_numbers = required_version.to_s.split(".")
32
+
33
+ versions.each do |value|
34
+ path_bracket_index = value.index("[")
35
+
36
+ begin
37
+ ver_number = value[0..path_bracket_index - 1].strip
38
+ current_version = Gem::Version.new(ver_number)
39
+ available_versions.append(current_version.to_s)
40
+ rescue ArgumentError => ex
41
+ UI.user_error!("Can't parse the version entry from dotnet output: #{ex}")
42
+ end
43
+
44
+ if params[:strict]
45
+ next unless current_version == required_version
46
+
47
+ success(required_version)
48
+ else
49
+ current_version_numbers = current_version.to_s.split(".")
50
+ all_correct = true
51
+
52
+ required_version_numbers.each_with_index do |required_version_number, index|
53
+ current_version_number = current_version_numbers[index]
54
+ next if required_version_number == current_version_number
55
+
56
+ all_correct = false
57
+ break
58
+ end
59
+
60
+ next unless all_correct
61
+
62
+ success(current_version)
63
+ end
64
+
65
+ found = true
66
+ break
67
+ end
68
+
69
+ error(required_version, available_versions) unless found
70
+ end
71
+
72
+ def self.success(version)
73
+ UI.success("Required .NET version has found: #{version}")
74
+ end
75
+
76
+ def self.error(version, available_versions)
77
+ str = [
78
+ "Required .NET version hasn't been found: #{version}",
79
+ "Available versions: #{available_versions}"
80
+ ].join("\n")
81
+
82
+ UI.user_error!(str)
83
+ end
84
+
85
+ def self.description
86
+ "Ensures the right version of .NET is installed and can be used"
87
+ end
88
+
89
+ def self.authors
90
+ ["CheeryLee"]
91
+ end
92
+
93
+ def self.is_supported?(platform)
94
+ true
95
+ end
96
+
97
+ def self.available_options
98
+ [
99
+ FastlaneCore::ConfigItem.new(
100
+ key: :version,
101
+ description: ".NET version to verify that is installed",
102
+ optional: false,
103
+ type: String,
104
+ verify_block: proc do |value|
105
+ UI.user_error!("The version of .NET to check is empty") unless value && !value.empty?
106
+ end
107
+ ),
108
+ FastlaneCore::ConfigItem.new(
109
+ key: :strict,
110
+ description: "Should the version be verified strictly (all 3 version numbers), or matching only the given version numbers (i.e. 6.0 == 6.0.x)",
111
+ optional: true,
112
+ default_value: true,
113
+ type: Boolean
114
+ )
115
+ ]
116
+ end
117
+
118
+ def self.category
119
+ :building
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,91 @@
1
+ require "fastlane/action"
2
+
3
+ module Fastlane
4
+ module Actions
5
+ module SharedValues
6
+ SF_MS_USERNAME = :SF_MS_USERNAME
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
11
+ end
12
+
13
+ class MsCredentialsAction < Action
14
+ def self.run(params)
15
+ Actions.lane_context[SharedValues::SF_MS_USERNAME] = params[:username]
16
+ Actions.lane_context[SharedValues::SF_MS_PASSWORD] = params[:password]
17
+ Actions.lane_context[SharedValues::SF_MS_TENANT_ID] = params[:tenant_id]
18
+ Actions.lane_context[SharedValues::SF_MS_CLIENT_ID] = params[:client_id]
19
+ Actions.lane_context[SharedValues::SF_MS_CLIENT_SECRET] = params[:client_secret]
20
+
21
+ UI.success("Credentials for Azure AD account is successfully saved for further actions")
22
+ end
23
+
24
+ def self.description
25
+ "Sets Azure AD account credentials"
26
+ end
27
+
28
+ def self.authors
29
+ ["CheeryLee"]
30
+ end
31
+
32
+ def self.is_supported?(platform)
33
+ [:windows].include?(platform)
34
+ end
35
+
36
+ def self.available_options
37
+ [
38
+ FastlaneCore::ConfigItem.new(
39
+ key: :username,
40
+ description: "The username of Azure AD account",
41
+ optional: false,
42
+ type: String,
43
+ verify_block: proc do |value|
44
+ UI.user_error!("Microsoft username can't be empty") unless value && !value.empty?
45
+ end
46
+ ),
47
+ FastlaneCore::ConfigItem.new(
48
+ key: :password,
49
+ description: "The password of Azure AD account",
50
+ optional: false,
51
+ type: String,
52
+ verify_block: proc do |value|
53
+ UI.user_error!("Microsoft password can't be empty") unless value && !value.empty?
54
+ end
55
+ ),
56
+ FastlaneCore::ConfigItem.new(
57
+ key: :tenant_id,
58
+ description: "The unique identifier of the Azure AD instance",
59
+ optional: false,
60
+ type: String,
61
+ verify_block: proc do |value|
62
+ UI.user_error!("Tenant ID can't be empty") unless value && !value.empty?
63
+ end
64
+ ),
65
+ FastlaneCore::ConfigItem.new(
66
+ key: :client_id,
67
+ description: "The ID of an application that would be associate to get working with Microsoft account",
68
+ optional: false,
69
+ type: String,
70
+ verify_block: proc do |value|
71
+ UI.user_error!("Client ID can't be empty") unless value && !value.empty?
72
+ end
73
+ ),
74
+ FastlaneCore::ConfigItem.new(
75
+ key: :client_secret,
76
+ description: "The unique secret string of an application that can be generated in Microsoft Partner Center",
77
+ optional: false,
78
+ type: String,
79
+ verify_block: proc do |value|
80
+ UI.user_error!("Client secret string can't be empty") unless value && !value.empty?
81
+ end
82
+ )
83
+ ]
84
+ end
85
+
86
+ def self.category
87
+ :misc
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,45 @@
1
+ require "fastlane/action"
2
+ require_relative "../msbuild/options"
3
+ require_relative "../msbuild/module"
4
+ require_relative "../actions_base/msbuild_action_base"
5
+
6
+ module Fastlane
7
+ module Actions
8
+ class MsbuildAction < MsbuildActionBase
9
+ def self.run(params)
10
+ Msbuild.config.certificate = nil
11
+ Msbuild.config.certificate_password = nil
12
+ Msbuild.config.certificate_thumbprint = nil
13
+ Msbuild.config.build_type = Msbuild::BuildType::GENERIC
14
+
15
+ super(params)
16
+ end
17
+
18
+ def self.description
19
+ "Executes MSBuild to build the application"
20
+ end
21
+
22
+ def self.authors
23
+ ["CheeryLee"]
24
+ end
25
+
26
+ def self.is_supported?(platform)
27
+ true
28
+ end
29
+
30
+ def self.rejected_options
31
+ %i[
32
+ appx_output_path
33
+ appx_output_name
34
+ appx_bundle_platforms
35
+ build_mode
36
+ skip_codesigning
37
+ ]
38
+ end
39
+
40
+ def self.category
41
+ :building
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,53 @@
1
+ require "fastlane/action"
2
+ require_relative "../msbuild/module"
3
+
4
+ module Fastlane
5
+ module Actions
6
+ module SharedValues
7
+ SF_MSBUILD_PATH = :SF_MSBUILD_PATH
8
+ SF_MSBUILD_TYPE = :SF_MSBUILD_TYPE
9
+ end
10
+
11
+ class MsbuildSelectAction < Action
12
+ def self.run(params)
13
+ path = (params || []).first.to_s
14
+ path = File.expand_path(path)
15
+
16
+ UI.user_error!("File '#{path}' doesn't exist") unless File.exist?(path)
17
+ UI.user_error!("Path to MSBuild executable or library required") if
18
+ path.empty? || (!path.end_with?("MSBuild.exe") && !path.end_with?("MSBuild.dll"))
19
+
20
+ Actions.lane_context[SharedValues::SF_MSBUILD_PATH] = path
21
+ Actions.lane_context[SharedValues::SF_MSBUILD_TYPE] = if path.end_with?("MSBuild.exe")
22
+ Msbuild::MsbuildType::EXE
23
+ else
24
+ Msbuild::MsbuildType::LIBRARY
25
+ end
26
+
27
+ UI.message("Setting MSBuild executable to '#{path}' for all next build steps")
28
+ end
29
+
30
+ def self.description
31
+ "Changes the MSBuild executable to use. Useful if you have multiple installed versions."
32
+ end
33
+
34
+ def self.authors
35
+ ["CheeryLee"]
36
+ end
37
+
38
+ def self.is_supported?(platform)
39
+ true
40
+ end
41
+
42
+ def self.example_code
43
+ [
44
+ 'msbuild_select("/cygdrive/c/Program\ Files/Microsoft\ Visual\ Studio/2022/Community/Msbuild/Current/Bin/MSBuild.exe")'
45
+ ]
46
+ end
47
+
48
+ def self.category
49
+ :building
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ require "fastlane/action"
2
+ require_relative "../msbuild/options"
3
+ require_relative "../msbuild/module"
4
+ require_relative "../actions_base/msbuild_action_base"
5
+
6
+ module Fastlane
7
+ module Actions
8
+ class NugetPackAction < MsbuildActionBase
9
+ def self.run(params)
10
+ Msbuild.config.certificate = nil
11
+ Msbuild.config.certificate_password = nil
12
+ Msbuild.config.certificate_thumbprint = nil
13
+ Msbuild.config.build_type = Msbuild::BuildType::NUGET
14
+
15
+ super(params)
16
+ end
17
+
18
+ def self.description
19
+ "Executes MSBuild to create a NuGet package"
20
+ end
21
+
22
+ def self.authors
23
+ ["CheeryLee"]
24
+ end
25
+
26
+ def self.is_supported?(platform)
27
+ true
28
+ end
29
+
30
+ def self.rejected_options
31
+ %i[
32
+ restore
33
+ appx_output_path
34
+ appx_output_name
35
+ appx_bundle_platforms
36
+ build_mode
37
+ skip_codesigning
38
+ ]
39
+ end
40
+
41
+ def self.category
42
+ :building
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,73 @@
1
+ require "fastlane/action"
2
+
3
+ module Fastlane
4
+ module Actions
5
+ module SharedValues
6
+ SF_CERTIFICATE_PATH = :SF_CERTIFICATE_PATH
7
+ SF_CERTIFICATE_PASSWORD = :SF_CERTIFICATE_PASSWORD
8
+ SF_CERTIFICATE_THUMBPRINT = :SF_CERTIFICATE_THUMBPRINT
9
+ end
10
+
11
+ class UpdateUwpSigningSettingsAction < Action
12
+ def self.run(params)
13
+ path = params[:certificate]
14
+
15
+ Actions.lane_context[SharedValues::SF_CERTIFICATE_PATH] = path
16
+ Actions.lane_context[SharedValues::SF_CERTIFICATE_PASSWORD] = params[:password]
17
+ Actions.lane_context[SharedValues::SF_CERTIFICATE_THUMBPRINT] = params[:thumbprint]
18
+
19
+ UI.message("Setting signing certificate to '#{path}' for all next build steps")
20
+ end
21
+
22
+ def self.description
23
+ "Configures UWP package signing settings. Works only on 'windows' platform. Values that would be set in this action will be applied to all next actions."
24
+ end
25
+
26
+ def self.details
27
+ "Works only on `windows` platform"
28
+ end
29
+
30
+ def self.authors
31
+ ["CheeryLee"]
32
+ end
33
+
34
+ def self.is_supported?(platform)
35
+ [:windows].include?(platform)
36
+ end
37
+
38
+ def self.available_options
39
+ [
40
+ FastlaneCore::ConfigItem.new(
41
+ key: :certificate,
42
+ description: "Path to the certificate to use",
43
+ optional: false,
44
+ type: String,
45
+ verify_block: proc do |value|
46
+ UI.user_error!("Path to certificate is invalid") unless value && !value.empty?
47
+ UI.user_error!("The provided path doesn't point to PFX-file") unless
48
+ File.exist?(File.expand_path(value)) && value.end_with?(".pfx")
49
+ end
50
+ ),
51
+ FastlaneCore::ConfigItem.new(
52
+ key: :password,
53
+ description: "The password for the private key in the certificate",
54
+ optional: true,
55
+ default_value: "",
56
+ type: String
57
+ ),
58
+ FastlaneCore::ConfigItem.new(
59
+ key: :thumbprint,
60
+ description: "This value must match the thumbprint in the signing certificate or be an empty string",
61
+ optional: true,
62
+ default_value: "",
63
+ type: String
64
+ )
65
+ ]
66
+ end
67
+
68
+ def self.category
69
+ :code_signing
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,218 @@
1
+ require "fastlane/action"
2
+ require_relative "../helper/ms_devcenter_helper"
3
+ require_relative "../msbuild/options"
4
+
5
+ module Fastlane
6
+ module Actions
7
+ class UploadMsStoreAction < Action
8
+ DEFAULT_TIMEOUT = 300
9
+
10
+ def self.run(params)
11
+ tenant_id = Actions.lane_context[SharedValues::SF_MS_TENANT_ID]
12
+ client_id = Actions.lane_context[SharedValues::SF_MS_CLIENT_ID]
13
+ client_secret = Actions.lane_context[SharedValues::SF_MS_CLIENT_SECRET]
14
+ app_id = params[:app_id]
15
+ path = params[:path]
16
+ timeout = params.values.include?(:timeout) && params[:timeout].positive? ? params[:timeout] : DEFAULT_TIMEOUT
17
+
18
+ UI.message("Acquiring authorization token for DevCenter ...")
19
+ auth_token = Helper::MsDevCenterHelper.acquire_authorization_token(tenant_id, client_id, client_secret, timeout)
20
+ UI.message("Authorization token was obtained")
21
+
22
+ UI.message("Creating submission for app #{app_id} ...")
23
+ submission_obj = Helper::MsDevCenterHelper.create_submission(app_id, auth_token, timeout)
24
+ submission_id = submission_obj["id"]
25
+ UI.message("Submission #{submission_id} created")
26
+
27
+ UI.message("Prepare ZIP blob for upload ...")
28
+ zip_path = create_blob_zip(File.expand_path(path))
29
+ UI.success("Blob is ready")
30
+
31
+ UI.message("Uploading ZIP blob ...")
32
+ Helper::MsDevCenterHelper.upload_blob(submission_obj["fileUploadUrl"], zip_path, timeout)
33
+ UI.success("ZIP blob uploaded successfully")
34
+
35
+ submission_obj = prepare_empty_submission(submission_obj)
36
+ submission_obj = add_package_to_submission(submission_obj, File.basename(path))
37
+
38
+ UI.message("Updating submission data ...")
39
+ Helper::MsDevCenterHelper.update_submission(app_id, submission_obj, auth_token, timeout)
40
+ UI.message("Updated successfully")
41
+
42
+ UI.message("Committing ...")
43
+ Helper::MsDevCenterHelper.commit_submission(app_id, submission_id, auth_token, timeout)
44
+
45
+ if params.values.include?(:skip_waiting_for_build_processing) &&
46
+ [true].include?(params[:skip_waiting_for_build_processing])
47
+ UI.success("Submission passed, but build processing were skipped. Check the Dev Center page.")
48
+ return
49
+
50
+ end
51
+
52
+ status = false
53
+ data = nil
54
+ until status
55
+ UI.message("Waiting for the submission to change the status - this may take a few minutes")
56
+ data = Helper::MsDevCenterHelper.get_submission_status(app_id, submission_id, auth_token, timeout)
57
+ status = data["status"] != "CommitStarted"
58
+ sleep(30) unless status
59
+ end
60
+
61
+ if data["status"] == "CommitFailed"
62
+ errors = data["statusDetails"]["errors"]
63
+ if errors.length == 1 && errors[0]["code"] == "InvalidState"
64
+ UI.important(
65
+ [
66
+ "All submission operations passed correctly, but there are some things that you need to proceed using DevCenter.",
67
+ "Message: #{errors[0]["details"]}"
68
+ ].join("\n")
69
+ )
70
+ return
71
+ end
72
+
73
+ errors.each do |error|
74
+ UI.error("Error code: #{error["code"]}\nMessage: #{error["details"]}")
75
+ end
76
+
77
+ UI.user_error!("Submission failed")
78
+ end
79
+
80
+ UI.success("Submission passed. Check the DevCenter page.")
81
+ end
82
+
83
+ def self.description
84
+ "Uploads new binary to Microsoft Partner Center"
85
+ end
86
+
87
+ def self.authors
88
+ ["CheeryLee"]
89
+ end
90
+
91
+ def self.is_supported?(platform)
92
+ [:windows].include?(platform)
93
+ end
94
+
95
+ def self.available_options
96
+ [
97
+ FastlaneCore::ConfigItem.new(
98
+ key: :timeout,
99
+ description: "The timeout for pushing to a server in seconds",
100
+ optional: true,
101
+ default_value: 0,
102
+ type: Integer
103
+ ),
104
+ FastlaneCore::ConfigItem.new(
105
+ key: :app_id,
106
+ description: "The Microsoft Store ID of an application",
107
+ optional: false,
108
+ type: String,
109
+ verify_block: proc do |value|
110
+ UI.user_error!("The Microsoft Store ID can't be empty") unless value && !value.empty?
111
+ end
112
+ ),
113
+ FastlaneCore::ConfigItem.new(
114
+ key: :skip_waiting_for_build_processing,
115
+ description: "If set to true, the action will only commit the submission and skip the remaining build validation",
116
+ optional: true,
117
+ default_value: false,
118
+ type: Fastlane::Boolean
119
+ ),
120
+ FastlaneCore::ConfigItem.new(
121
+ key: :path,
122
+ description: "The file path to the package to be uploaded",
123
+ optional: false,
124
+ type: String,
125
+ verify_block: proc do |value|
126
+ UI.user_error!("Path to UWP package is invalid") unless value && !value.empty?
127
+
128
+ format_valid = false
129
+ Msbuild::Options::PACKAGE_FORMATS.each do |extension|
130
+ if value.end_with?(extension)
131
+ format_valid = true
132
+ break
133
+ end
134
+ end
135
+
136
+ UI.user_error!("The provided path doesn't point to UWP file") unless
137
+ File.exist?(File.expand_path(value)) && format_valid
138
+ end
139
+ )
140
+ ]
141
+ end
142
+
143
+ def self.category
144
+ :production
145
+ end
146
+
147
+ def self.create_blob_zip(package_path)
148
+ File.delete(File.join(File.dirname(package_path), "blob.zip"))
149
+ zip_path = File.join(File.dirname(package_path), "blob.zip")
150
+
151
+ Zip::File.open(zip_path, create: true) do |file|
152
+ file.add(File.basename(package_path), package_path)
153
+
154
+ screenshot_path = File.join(Helper::SapfireHelper.root_plugin_location, "assets", "ms_example_screenshot.png")
155
+ file.add("ms_example_screenshot.png", File.expand_path(screenshot_path))
156
+ end
157
+
158
+ zip_path
159
+ end
160
+
161
+ def self.add_package_to_submission(submission_obj, file_name)
162
+ check_submission(submission_obj)
163
+ UI.user_error!("Package file name can't be null or empty") if file_name.nil? || file_name.empty?
164
+
165
+ key = "applicationPackages"
166
+ package = {
167
+ "fileName": file_name,
168
+ "fileStatus": "PendingUpload",
169
+ "minimumDirectXVersion": "None",
170
+ "minimumSystemRam": "None"
171
+ }
172
+
173
+ submission_obj[key] = [] if submission_obj[key].empty?
174
+ submission_obj[key].append(package)
175
+ submission_obj
176
+ end
177
+
178
+ def self.prepare_empty_submission(submission_obj)
179
+ check_submission(submission_obj)
180
+
181
+ submission_obj["applicationCategory"] = "UtilitiesAndTools" if submission_obj["applicationCategory"] == "NotSet"
182
+ submission_obj["targetPublishMode"] = "Manual"
183
+
184
+ if submission_obj["allowTargetFutureDeviceFamilies"].empty?
185
+ submission_obj["allowTargetFutureDeviceFamilies"] = {
186
+ "Desktop": false,
187
+ "Mobile": false,
188
+ "Holographic": false,
189
+ "Xbox": false
190
+ }
191
+ end
192
+
193
+ if submission_obj["listings"].empty?
194
+ submission_obj["listings"]["en-us"] = {}
195
+ submission_obj["listings"]["en-us"]["baseListing"] = {
196
+ "description": "1",
197
+ "privacyPolicy": "https://example.com",
198
+ "images": [
199
+ {
200
+ "fileName": "ms_example_screenshot.png",
201
+ "fileStatus": "PendingUpload",
202
+ "imageType": "Screenshot"
203
+ }
204
+ ]
205
+ }
206
+ end
207
+
208
+ submission_obj
209
+ end
210
+
211
+ def self.check_submission(submission_obj)
212
+ UI.user_error!("Submission data object need to be provided") if submission_obj.nil?
213
+ end
214
+
215
+ private_constant(:DEFAULT_TIMEOUT)
216
+ end
217
+ end
218
+ end