xamarin-test-cloud 2.0.3 → 2.1.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/CHANGELOG.md +13 -0
- data/lib/xamarin-test-cloud/cli.rb +416 -154
- data/lib/xamarin-test-cloud/dsym.rb +5 -7
- data/lib/xamarin-test-cloud/test_file.rb +2 -2
- data/lib/xamarin-test-cloud/version.rb +1 -1
- metadata +3 -4
- data/lib/xamarin-test-cloud/cli.rb alias +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7179d836cc88e3266185b3d9cd68afa6b8272681
|
4
|
+
data.tar.gz: 50bb75d45e930271faaa5a28ae6f718895790a6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2adca474985c4505d9dbe98b5ae5c0e0da1365d921578328f2a3a21a7f13d84fdc8ef07e405cb638b8042bb3543602b49b642bac55117bc37fb9c796d5ed9573
|
7
|
+
data.tar.gz: 2ed5fcd3105e9622d69c1e88318b4c64bf4fced3bc516877c7cc6804385739f46337fe7acafba81e2f80a0fb2681b8531b09f7d35d6eda65c1f9f739bde642f9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
### 2.1.0
|
2
|
+
|
3
|
+
* CLI#collect\_files\_with\_glob should collect . files and skip anything
|
4
|
+
under \_\_MACOSX #89
|
5
|
+
* Fix the collection of included files #87
|
6
|
+
* Add `prepare` command to generate an upload manifest #85
|
7
|
+
|
8
|
+
### 2.0.3
|
9
|
+
|
10
|
+
* CLI: add calabash=true to upload data #82
|
11
|
+
* Support --include flag #81
|
12
|
+
* Gem: force HTTPClient 2.7.1 or higher #80
|
13
|
+
|
1
14
|
### 2.0.2
|
2
15
|
|
3
16
|
* Use otool-classic to check for the CalabashServer whenever it is
|
@@ -41,7 +41,7 @@ module XamarinTestCloud
|
|
41
41
|
:include_files_input,
|
42
42
|
:locale, :series, :session_id
|
43
43
|
|
44
|
-
|
44
|
+
attr_reader :included_files_map
|
45
45
|
|
46
46
|
def self.exit_on_failure?
|
47
47
|
true
|
@@ -63,6 +63,7 @@ module XamarinTestCloud
|
|
63
63
|
FILE_UPLOAD_ENDPOINT = 'upload2'
|
64
64
|
FORM_URL_ENCODED_ENDPOINT = 'upload'
|
65
65
|
|
66
|
+
MANIFEST_SCHEMA_VERSION = "1.0.0"
|
66
67
|
|
67
68
|
def self.source_root
|
68
69
|
File.join(File.dirname(__FILE__), '..')
|
@@ -134,8 +135,7 @@ module XamarinTestCloud
|
|
134
135
|
:type => :boolean,
|
135
136
|
:default => false
|
136
137
|
|
137
|
-
|
138
|
-
#A list of items which are files or folders in the workspace.
|
138
|
+
# A list of items which are files or folders in the workspace.
|
139
139
|
# Must be a path relative to workspace and
|
140
140
|
# must not refer outside (e.g. no usage of ../ etc). Example --include .xtc foo
|
141
141
|
method_option 'include',
|
@@ -188,27 +188,8 @@ module XamarinTestCloud
|
|
188
188
|
$stdout = @async_log
|
189
189
|
end
|
190
190
|
|
191
|
-
|
192
|
-
|
193
|
-
raise ValidationError, "App is not a file: #{app_path}"
|
194
|
-
end
|
195
|
-
|
196
|
-
if shared_runtime?(app_path)
|
197
|
-
puts "Xamarin Test Cloud doesn't yet support shared runtime apps."
|
198
|
-
puts "To test your app it needs to be compiled for release."
|
199
|
-
puts "You can learn how to compile you app for release here:"
|
200
|
-
puts "http://docs.xamarin.com/guides/android/deployment%2C_testing%2C_and_metrics/publishing_an_application/part_1_-_preparing_an_application_for_release"
|
201
|
-
# TODO Change this to: "Shared runtime apps are not supported."
|
202
|
-
raise ValidationError, "Aborting"
|
203
|
-
end
|
204
|
-
|
205
|
-
app_extension = File.extname(app_path)
|
206
|
-
unless /ipa/i.match(app_extension) || /apk/i.match(app_extension)
|
207
|
-
raise ValidationError, "App #{app_path} must be an .ipa or .apk file"
|
208
|
-
end
|
209
|
-
|
210
|
-
|
211
|
-
self.app = app_path
|
191
|
+
# Verifies the app argument and sets the @app instance variable
|
192
|
+
verify_app!(app)
|
212
193
|
|
213
194
|
self.user = options['user']
|
214
195
|
|
@@ -230,36 +211,15 @@ module XamarinTestCloud
|
|
230
211
|
|
231
212
|
self.priority = options['priority']
|
232
213
|
|
233
|
-
self.skip_config_check = options['skip-config-check']
|
234
214
|
|
235
215
|
self.include_files_input = options['include']
|
236
216
|
|
237
217
|
# Resolves the workspace and sets the @derived_workspace variable.
|
238
218
|
expect_features_directory_in_workspace
|
239
219
|
|
240
|
-
#
|
241
|
-
|
242
|
-
|
243
|
-
default_config = File.join(derived_workspace, 'config', 'cucumber.yml')
|
244
|
-
# TODO .config/cucumber.yml is valid
|
245
|
-
# TODO cucumber.yaml is valid
|
246
|
-
if File.exist?(default_config) && self.config.nil?
|
247
|
-
# TODO Reword the header.
|
248
|
-
log_header 'Warning: Detected cucumber.yml config file, but no --config specified'
|
249
|
-
|
250
|
-
# TODO Reword the message and pass to raise as message.
|
251
|
-
puts "Please specify --config #{default_config}"
|
252
|
-
puts 'and specify a profile via --profile'
|
253
|
-
puts 'If you know what you are doing you can skip this check with'
|
254
|
-
puts '--skip-config-check'
|
255
|
-
|
256
|
-
# TODO This error message is wrong.
|
257
|
-
# It should be cucumber.yml detected by no --config option set.
|
258
|
-
raise ValidationError, "#{default_config} detected but no profile selected."
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
self.included_files_map = parse_included_folders
|
220
|
+
# Verifies the --config and --profile options and sets these variables:
|
221
|
+
# @config, @profile, @skip_config_check
|
222
|
+
verify_cucumber_config_and_profile!
|
263
223
|
|
264
224
|
if Environment.debug?
|
265
225
|
puts "Host = #{self.host}"
|
@@ -273,11 +233,10 @@ module XamarinTestCloud
|
|
273
233
|
puts "Config = #{self.config}"
|
274
234
|
puts "Profile = #{self.profile}"
|
275
235
|
puts "dSym = #{self.dsym}"
|
276
|
-
puts "Include = #{
|
236
|
+
puts "Include = #{included_files_map}"
|
277
237
|
end
|
278
238
|
|
279
|
-
|
280
|
-
#Argument parsing done
|
239
|
+
# Argument parsing done
|
281
240
|
|
282
241
|
test_jon_data = submit_test_job(device_selection_data)
|
283
242
|
if self.dry_run
|
@@ -332,11 +291,197 @@ module XamarinTestCloud
|
|
332
291
|
end
|
333
292
|
end
|
334
293
|
|
294
|
+
desc "prepare <APP>",
|
295
|
+
"Prepares workspace and creates a manifest of files to be uploaded for test"
|
296
|
+
method_option :config,
|
297
|
+
:desc => "Cucumber configuration file (cucumber.yml)",
|
298
|
+
:aliases => "-c",
|
299
|
+
:type => :string
|
300
|
+
|
301
|
+
method_option :profile,
|
302
|
+
:desc => "Profile to run (profile from Cucumber configuration file)",
|
303
|
+
:aliases => "-p",
|
304
|
+
:type => :string
|
305
|
+
|
306
|
+
method_option :workspace,
|
307
|
+
:desc => "Alternate path to your Calabash workspace",
|
308
|
+
:aliases => "-w",
|
309
|
+
:type => :string
|
310
|
+
|
311
|
+
method_option "test-parameters",
|
312
|
+
:desc => "Example: -params username:nat@xamarin.com password:xamarin)",
|
313
|
+
:aliases => "-params",
|
314
|
+
:type => :hash,
|
315
|
+
:default => {}
|
316
|
+
|
317
|
+
method_option "skip-config-check",
|
318
|
+
:desc => "Force running without Cucumber profile (cucumber.yml)",
|
319
|
+
:type => :boolean,
|
320
|
+
:default => false
|
321
|
+
|
322
|
+
method_option "artifacts-dir",
|
323
|
+
:desc => "Directory where the test files should be staged.",
|
324
|
+
:type => :string,
|
325
|
+
:required => true
|
326
|
+
|
327
|
+
# A list of items which are files or folders in the workspace.
|
328
|
+
# Must be a path relative to workspace and
|
329
|
+
# must not refer outside (e.g. no usage of ../ etc). Example --include .xtc foo
|
330
|
+
method_option 'include',
|
331
|
+
:desc => 'Include folders or files in workspace in addition the features folder.',
|
332
|
+
:aliases => '-i',
|
333
|
+
:type => :array,
|
334
|
+
:default => []
|
335
|
+
|
336
|
+
def prepare(app)
|
337
|
+
@include_files_input = options[:include]
|
338
|
+
artifact_directory = File.expand_path(options["artifacts-dir"])
|
339
|
+
|
340
|
+
# Validates and sets the @app instance variable.
|
341
|
+
verify_app!(app)
|
342
|
+
|
343
|
+
# Resolves the workspace and sets the @derived_workspace variable.
|
344
|
+
expect_features_directory_in_workspace
|
345
|
+
|
346
|
+
# Verifies the --config and --profile options and sets these variables:
|
347
|
+
# @config, @profile, @skip_config_check
|
348
|
+
verify_cucumber_config_and_profile!
|
349
|
+
|
350
|
+
require "xamarin-test-cloud/tmpdir"
|
351
|
+
bundle_package_dir = XamarinTestCloud::TmpDir.mktmpdir
|
352
|
+
|
353
|
+
stage_gemfile_and_bundle_package(bundle_package_dir)
|
354
|
+
|
355
|
+
files = collect_test_suite_files(bundle_package_dir)
|
356
|
+
|
357
|
+
FileUtils.mkdir_p(artifact_directory)
|
358
|
+
manifest_file = File.join(artifact_directory, "manifest.json")
|
359
|
+
|
360
|
+
log_header("Preparing the Artifact Directory")
|
361
|
+
test_parameters = options["test-parameters"]
|
362
|
+
|
363
|
+
manifest = generate_manifest_hash(files, test_parameters)
|
364
|
+
write_manifest_to_file(manifest, manifest_file)
|
365
|
+
|
366
|
+
puts ""
|
367
|
+
puts "Copied files to:"
|
368
|
+
puts " #{File.expand_path(artifact_directory)}"
|
369
|
+
puts ""
|
370
|
+
puts "Wrote upload manifest to:"
|
371
|
+
puts " #{File.expand_path(manifest_file)}"
|
372
|
+
|
373
|
+
files.each do |test_file|
|
374
|
+
target = File.join(artifact_directory, test_file.remote_path)
|
375
|
+
basedir = File.dirname(target)
|
376
|
+
FileUtils.mkdir_p(basedir)
|
377
|
+
FileUtils.cp(test_file.path, target)
|
378
|
+
end
|
379
|
+
|
380
|
+
end
|
335
381
|
|
336
382
|
default_task :submit
|
337
383
|
|
338
384
|
no_tasks do
|
339
385
|
|
386
|
+
# TODO: move to separate module/class
|
387
|
+
def expect_app_exists_at_path(app_path)
|
388
|
+
unless File.exist?(File.expand_path(app_path))
|
389
|
+
raise ValidationError, %Q[
|
390
|
+
App does not exist at path:
|
391
|
+
|
392
|
+
#{File.expand_path(app_path)}
|
393
|
+
|
394
|
+
]
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# TODO: move to separate module/class
|
399
|
+
def expect_apk_or_ipa(app_path)
|
400
|
+
app_extension = File.extname(app_path)
|
401
|
+
unless /ipa/i.match(app_extension) || /apk/i.match(app_extension)
|
402
|
+
raise ValidationError, %Q[
|
403
|
+
App must be an .ipa or .apk file. Found:
|
404
|
+
|
405
|
+
#{app_path}
|
406
|
+
|
407
|
+
with extension: #{app_extension}
|
408
|
+
|
409
|
+
]
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# TODO: move to separate module/class
|
414
|
+
def expect_no_shared_runtime(app_path)
|
415
|
+
if shared_runtime?(app_path)
|
416
|
+
raise ValidationError, %Q[
|
417
|
+
Xamarin Test Cloud does not support shared runtime apps.
|
418
|
+
|
419
|
+
To test your app it needs to be compiled for release.
|
420
|
+
|
421
|
+
You can learn how to compile your app for release here:
|
422
|
+
|
423
|
+
http://docs.xamarin.com/guides/android/deployment%2C_testing%2C_and_metrics/publishing_an_application/part_1_-_preparing_an_application_for_release
|
424
|
+
|
425
|
+
]
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
# TODO: move to separate module/class
|
430
|
+
def expect_ipa_linked_with_calabash(app_path)
|
431
|
+
# Cannot use #is_ios because that method depends on the @app instance
|
432
|
+
# variable which is not set when this method is called.
|
433
|
+
return nil if !app_path.end_with?(".ipa")
|
434
|
+
|
435
|
+
# otool does not exist in non-macOS environments. We have to rely on
|
436
|
+
# the Test Cloud to perform the validation.
|
437
|
+
return nil if !Environment.macos_env?
|
438
|
+
|
439
|
+
require "xamarin-test-cloud/tmpdir"
|
440
|
+
tmpdir = TmpDir.mktmpdir
|
441
|
+
|
442
|
+
unzip_file(app_path, tmpdir)
|
443
|
+
|
444
|
+
payload_dir = File.join(tmpdir, "Payload")
|
445
|
+
|
446
|
+
if !File.directory?(payload_dir)
|
447
|
+
raise ValidationError, %Q[
|
448
|
+
Did not find a Payload directory after expanding the ipa.
|
449
|
+
|
450
|
+
#{app_path}
|
451
|
+
|
452
|
+
The .ipa was not packaged correctly.
|
453
|
+
|
454
|
+
]
|
455
|
+
end
|
456
|
+
|
457
|
+
app_dir = Dir.foreach("#{tmpdir}/Payload").find { |d| /\.app$/.match(d) }
|
458
|
+
res = check_for_calabash_server(tmpdir, app_dir)
|
459
|
+
|
460
|
+
if /CalabashServer/.match(res)
|
461
|
+
puts "ipa: #{app_path} *contains* calabash.framework"
|
462
|
+
else
|
463
|
+
raise ValidationError, %Q[
|
464
|
+
|
465
|
+
The ipa does not contain an app that is linked with Calabash.
|
466
|
+
|
467
|
+
Your app must link the calabash.framework at compile time or it must dynamically
|
468
|
+
load (in code) a Calabash dylib.
|
469
|
+
|
470
|
+
https://github.com/calabash/calabash-ios/wiki/Tutorial%3A-How-to-add-Calabash-to-Xcode
|
471
|
+
]
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def verify_app!(app_path)
|
476
|
+
expanded = File.expand_path(app_path)
|
477
|
+
expect_app_exists_at_path(expanded)
|
478
|
+
expect_apk_or_ipa(expanded)
|
479
|
+
expect_no_shared_runtime(expanded)
|
480
|
+
expect_ipa_linked_with_calabash(expanded)
|
481
|
+
|
482
|
+
@app = expanded
|
483
|
+
end
|
484
|
+
|
340
485
|
def dsym
|
341
486
|
if @dsym.nil?
|
342
487
|
value = options["dsym-file"]
|
@@ -437,10 +582,6 @@ module XamarinTestCloud
|
|
437
582
|
log "Packaging gems in: #{tmpdir}"
|
438
583
|
end
|
439
584
|
|
440
|
-
# TODO Move to common expect_valid_application
|
441
|
-
# TODO Rename: does not need to extract a test server
|
442
|
-
verify_app_and_extract_test_server
|
443
|
-
|
444
585
|
stage_gemfile_and_bundle_package(tmpdir)
|
445
586
|
|
446
587
|
log_header('Verifying dependencies')
|
@@ -469,6 +610,7 @@ module XamarinTestCloud
|
|
469
610
|
log_header('Uploading negotiated files')
|
470
611
|
|
471
612
|
upload_data = {
|
613
|
+
'calabash' => true,
|
472
614
|
'files' => digests_and_files,
|
473
615
|
'paths' => remote_paths,
|
474
616
|
'user' => self.user,
|
@@ -794,10 +936,16 @@ and try submitting again.
|
|
794
936
|
files
|
795
937
|
end
|
796
938
|
|
939
|
+
def collect_file?(path)
|
940
|
+
File.file?(path) &&
|
941
|
+
File.basename(path) != ".DS_Store" &&
|
942
|
+
!path[/__MACOSX/]
|
943
|
+
end
|
944
|
+
|
797
945
|
# Returns file paths as Strings
|
798
946
|
def collect_files_with_glob(glob)
|
799
|
-
Dir.glob(glob).select do |path|
|
800
|
-
|
947
|
+
Dir.glob(glob, File::FNM_DOTMATCH).select do |path|
|
948
|
+
collect_file?(path)
|
801
949
|
end
|
802
950
|
end
|
803
951
|
|
@@ -828,10 +976,26 @@ and try submitting again.
|
|
828
976
|
|
829
977
|
def collect_included_files(tmpdir)
|
830
978
|
collected_files = []
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
979
|
+
included_files_map.each_pair do |source, target|
|
980
|
+
# Use File.expand_path to handle the Windows case where the user passes:
|
981
|
+
# --workspace "test-cloud\ios"
|
982
|
+
# --include ".xtc\sample.txt"
|
983
|
+
#
|
984
|
+
# A File.join will result in:
|
985
|
+
# /path/to/test-cloud/ios/.xtc\sample.txt
|
986
|
+
# because the join naively appends the ".xtc\sample.txt"
|
987
|
+
# Use File.expand_path to handle the /
|
988
|
+
tmp_target = File.expand_path(File.join(tmpdir, target))
|
989
|
+
|
990
|
+
FileUtils.mkdir_p(File.dirname(tmp_target))
|
991
|
+
FileUtils.cp_r(source, tmp_target)
|
992
|
+
|
993
|
+
if File.directory?(tmp_target)
|
994
|
+
collect_files_with_glob(File.join(tmpdir,target,"**","*")).map do |file|
|
995
|
+
collected_files << TestFile.new(file, tmpdir)
|
996
|
+
end
|
997
|
+
else
|
998
|
+
collected_files << TestFile.new(tmp_target, tmpdir)
|
835
999
|
end
|
836
1000
|
end
|
837
1001
|
collected_files
|
@@ -893,30 +1057,6 @@ and try submitting again.
|
|
893
1057
|
end
|
894
1058
|
end
|
895
1059
|
|
896
|
-
# TODO: move to separate module/class
|
897
|
-
# TODO: fix the detection algorithm - it is broken
|
898
|
-
# TODO: remove the Frank check
|
899
|
-
# https://github.com/xamarinhq/test-cloud-command-line/issues/19
|
900
|
-
def validate_ipa(ipa)
|
901
|
-
result = false
|
902
|
-
dir = Dir.mktmpdir #do |dir|
|
903
|
-
|
904
|
-
unzip_file(ipa, dir)
|
905
|
-
unless File.directory?("#{dir}/Payload") #macos only
|
906
|
-
raise ValidationError, "Unzipping #{ipa} to #{dir} failed: Did not find a Payload directory (invalid .ipa)."
|
907
|
-
end
|
908
|
-
app_dir = Dir.foreach("#{dir}/Payload").find { |d| /\.app$/.match(d) }
|
909
|
-
res = check_for_calabash_server(dir, app_dir)
|
910
|
-
|
911
|
-
if /CalabashServer/.match(res)
|
912
|
-
puts "ipa: #{ipa} *contains* calabash.framework"
|
913
|
-
result = :calabash
|
914
|
-
end
|
915
|
-
|
916
|
-
result
|
917
|
-
end
|
918
|
-
|
919
|
-
|
920
1060
|
def log(message)
|
921
1061
|
if message.is_a? Array
|
922
1062
|
message.each { |m| log(m) }
|
@@ -934,27 +1074,6 @@ and try submitting again.
|
|
934
1074
|
end
|
935
1075
|
end
|
936
1076
|
|
937
|
-
# TODO: rename: does not need to extract or return the server
|
938
|
-
def verify_app_and_extract_test_server
|
939
|
-
server = nil
|
940
|
-
|
941
|
-
unless File.exist?(app)
|
942
|
-
raise ValidationError, "No such file: #{app}"
|
943
|
-
end
|
944
|
-
unless (/\.(apk|ipa)$/ =~ app)
|
945
|
-
raise ValidationError, '<APP> should be either an ipa or apk file.'
|
946
|
-
end
|
947
|
-
if is_ios? && Environment.macos_env?
|
948
|
-
log_header('Checking ipa for linking with Calabash')
|
949
|
-
server = validate_ipa(app)
|
950
|
-
abort_unless(server) do
|
951
|
-
puts 'The .ipa file does not seem to be linked with Calabash.'
|
952
|
-
puts 'Verify that your app is linked correctly.'
|
953
|
-
end
|
954
|
-
end
|
955
|
-
server
|
956
|
-
end
|
957
|
-
|
958
1077
|
# TODO Rename or remove; abort is not the right verb - use exit
|
959
1078
|
# +1 for remove
|
960
1079
|
def abort(&block)
|
@@ -982,12 +1101,15 @@ and try submitting again.
|
|
982
1101
|
end
|
983
1102
|
|
984
1103
|
# TODO Move to a module
|
1104
|
+
# TODO Needs tests
|
985
1105
|
def shared_runtime?(app_path)
|
986
1106
|
f = files(app_path)
|
987
1107
|
f.any? do |file|
|
988
1108
|
filename = file[:filename]
|
989
1109
|
if filename.end_with?("libmonodroid.so")
|
990
|
-
file[:size] < 120 * 1024 && f.none?
|
1110
|
+
file[:size] < 120 * 1024 && f.none? do |x|
|
1111
|
+
x[:filename] == filename.sub("libmonodroid.so", "libmonosgen-2.0.so")
|
1112
|
+
end
|
991
1113
|
end
|
992
1114
|
end
|
993
1115
|
end
|
@@ -1001,52 +1123,186 @@ and try submitting again.
|
|
1001
1123
|
end
|
1002
1124
|
end
|
1003
1125
|
|
1004
|
-
# TODO: extract to a module
|
1005
|
-
# TODO: replace unless/else branches
|
1006
|
-
def parse_and_set_config_and_profile
|
1007
|
-
config_path = options[:config]
|
1008
1126
|
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1127
|
+
# TODO: extract this method to a module
|
1128
|
+
# TODO: .config/cucumber.yml is a valid cucumber profile
|
1129
|
+
# TODO: cucumber.yaml and cucumber.yml are both valid names
|
1130
|
+
#
|
1131
|
+
# Raises if there is config/cucumber.yml file but no --config option is
|
1132
|
+
# passed.
|
1133
|
+
#
|
1134
|
+
# Check can be skipped by passing --skip-config-check.
|
1135
|
+
#
|
1136
|
+
# This method, sadly, has a preconditions: @config and @skip_config_check
|
1137
|
+
# must be set correctly before calling this method.
|
1138
|
+
def expect_config_option_if_cucumber_config_file_exists
|
1139
|
+
return nil if config
|
1140
|
+
return nil if skip_config_check
|
1141
|
+
|
1142
|
+
default_config = File.join(derived_workspace, "config", "cucumber.yml")
|
1143
|
+
if File.exist?(default_config)
|
1144
|
+
raise ValidationError, %Q[
|
1145
|
+
Detected a cucumber configuration file, but no --config option was specified.
|
1146
|
+
|
1147
|
+
#{default_config}
|
1148
|
+
|
1149
|
+
You can pass the cucumber configuration file to the uploader using:
|
1150
|
+
|
1151
|
+
--config #{default_config}
|
1152
|
+
|
1153
|
+
and specify a profile using the --profile option.
|
1154
|
+
|
1155
|
+
You can skip this check using the --skip-config-check option, but this is not
|
1156
|
+
recommended.
|
1157
|
+
|
1158
|
+
]
|
1012
1159
|
end
|
1160
|
+
end
|
1013
1161
|
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
raise ValidationError, "Config file does not exist #{config_path}"
|
1018
|
-
end
|
1162
|
+
# TODO: extract this method to a module
|
1163
|
+
def resolve_cucumber_config_path(path)
|
1164
|
+
return nil if !path
|
1019
1165
|
|
1020
|
-
|
1021
|
-
|
1022
|
-
rescue Exception => e
|
1023
|
-
puts "Unable to parse #{config_path} as yml. Is this your Cucumber.yml file?"
|
1024
|
-
raise ValidationError, e
|
1025
|
-
end
|
1166
|
+
expanded = File.expand_path(path)
|
1167
|
+
return expanded if expanded == path
|
1026
1168
|
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1169
|
+
workspace = derived_workspace
|
1170
|
+
# Use File.expand_path to handle the Windows case where the user passes:
|
1171
|
+
# --workspace "test-cloud\ios"
|
1172
|
+
# --config "config\cucumber.yml"
|
1173
|
+
#
|
1174
|
+
# A File.join will result in:
|
1175
|
+
# /path/to/test-cloud/ios/config\cucumber.yml
|
1176
|
+
# because the join naively appends the "config\cucumber.yml".
|
1177
|
+
File.expand_path(File.join(workspace, path))
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
# TODO: extract this method to a module
|
1181
|
+
#
|
1182
|
+
# Sets @config to a TestFile instance
|
1183
|
+
# Sets @skip_config_check to option passed on the CLI
|
1184
|
+
# Sets @profile to option passed on the CLI
|
1185
|
+
#
|
1186
|
+
# Raises if there is problem parsing or interpreting the profile with
|
1187
|
+
# respect to the configuration file.
|
1188
|
+
#
|
1189
|
+
# Raises if there is config/cucumber.yml file but no --config option is
|
1190
|
+
# passed.
|
1191
|
+
def verify_cucumber_config_and_profile!
|
1192
|
+
config = options[:config]
|
1193
|
+
profile = options[:profile]
|
1194
|
+
|
1195
|
+
if profile && !config
|
1196
|
+
raise ValidationError, %Q[
|
1197
|
+
|
1198
|
+
The --profile option was set without a --config option.
|
1199
|
+
|
1200
|
+
If a --profile is specified, then a cucumber configuration file is required.
|
1201
|
+
|
1202
|
+
https://github.com/cucumber/cucumber/wiki/cucumber.yml
|
1203
|
+
|
1204
|
+
]
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
# Defaults to false
|
1208
|
+
@skip_config_check = options["skip-config-check"]
|
1209
|
+
|
1210
|
+
if !config
|
1211
|
+
@config = nil
|
1212
|
+
@profile = nil
|
1213
|
+
expect_config_option_if_cucumber_config_file_exists
|
1214
|
+
else
|
1215
|
+
config_path = resolve_cucumber_config_path(config)
|
1216
|
+
|
1217
|
+
if !File.exist?(config_path)
|
1218
|
+
raise ValidationError, %Q[
|
1219
|
+
File specified by --config option does not exist:
|
1220
|
+
|
1221
|
+
#{config_path}
|
1222
|
+
|
1223
|
+
]
|
1030
1224
|
end
|
1031
1225
|
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1226
|
+
if profile
|
1227
|
+
expect_profile_exists_in_cucumber_config(config_path, profile)
|
1228
|
+
@profile = profile
|
1035
1229
|
else
|
1036
|
-
|
1037
|
-
raise ValidationError, "Config file provided did not contain profile #{profile}."
|
1038
|
-
else
|
1039
|
-
puts "Using profile #{profile}..."
|
1040
|
-
self.profile = profile
|
1041
|
-
end
|
1042
|
-
end
|
1043
|
-
else
|
1044
|
-
if options[:profile]
|
1045
|
-
raise ValidationError, 'Profile selected but no config file provided.'
|
1230
|
+
@profile = nil
|
1046
1231
|
end
|
1232
|
+
@config = TestFile.cucumber_config(config_path)
|
1233
|
+
end
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
# TODO: extract this method to a module
|
1237
|
+
def expect_profile_exists_in_cucumber_config(config_path, profile)
|
1238
|
+
config_yml = {}
|
1239
|
+
|
1240
|
+
begin
|
1241
|
+
config_yml = YAML.load(ERB.new(File.read(config_path)).result)
|
1242
|
+
rescue => e
|
1243
|
+
raise ValidationError, %Q[
|
1244
|
+
|
1245
|
+
#{e.message}
|
1246
|
+
|
1247
|
+
Unable to parse --config option as yml:
|
1248
|
+
|
1249
|
+
#{config_path}
|
1250
|
+
|
1251
|
+
]
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
if Environment.debug?
|
1255
|
+
puts "Parsed Cucumber config as:"
|
1256
|
+
puts config_yml.inspect
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
if !config_yml[profile]
|
1260
|
+
raise ValidationError, %Q[
|
1261
|
+
The cucumber configuration file specified by the --config option does not
|
1262
|
+
contain the profile specified by --profile option:
|
1263
|
+
|
1264
|
+
:config => #{config_path}
|
1265
|
+
:profile => #{profile}
|
1266
|
+
|
1267
|
+
]
|
1047
1268
|
end
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
# TODO Make --include'd paths generic when possible (see code comment below)
|
1272
|
+
def generate_manifest_hash(test_files, test_parameters)
|
1273
|
+
files = test_files.map do |test_file|
|
1274
|
+
path = test_file.remote_path
|
1275
|
+
if path[/features/]
|
1276
|
+
"features"
|
1277
|
+
elsif path[/vendor/]
|
1278
|
+
"vendor"
|
1279
|
+
else
|
1280
|
+
# --include'd files. It is not possible to filter these to a single
|
1281
|
+
# directory without inspecting the --include option itself.
|
1282
|
+
# Consider the example where --include is `config/xtc-users.json`.
|
1283
|
+
# We cannot filter to `config` because the config directory might
|
1284
|
+
# include a cucumber.yml or some other file that the user does _not_
|
1285
|
+
# want to upload.
|
1286
|
+
path
|
1287
|
+
end
|
1288
|
+
end.uniq!
|
1289
|
+
|
1290
|
+
{
|
1291
|
+
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
1292
|
+
files: files,
|
1293
|
+
testFramework: {
|
1294
|
+
name: "calabash",
|
1295
|
+
data: test_parameters
|
1296
|
+
}
|
1297
|
+
}
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
def write_manifest_to_file(manifest, manifest_file)
|
1301
|
+
json = JSON.pretty_generate(manifest)
|
1048
1302
|
|
1049
|
-
|
1303
|
+
File.open(manifest_file, "w:UTF-8") do |file|
|
1304
|
+
file.write(json)
|
1305
|
+
end
|
1050
1306
|
end
|
1051
1307
|
|
1052
1308
|
def included_files_map
|
@@ -1054,24 +1310,24 @@ and try submitting again.
|
|
1054
1310
|
end
|
1055
1311
|
|
1056
1312
|
def parse_included_folders
|
1057
|
-
return {} unless self.include_files_input
|
1058
1313
|
basedir = derived_workspace
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1314
|
+
source_target_map = {}
|
1315
|
+
include_files_input.each do |file|
|
1316
|
+
source = File.join(basedir, file)
|
1317
|
+
expect_valid_included_file(source, file)
|
1318
|
+
source_target_map[source] = file
|
1064
1319
|
end
|
1065
|
-
|
1320
|
+
source_target_map
|
1066
1321
|
end
|
1067
1322
|
|
1068
|
-
def
|
1323
|
+
def expect_valid_included_file(src, tgt)
|
1069
1324
|
unless File.exists?(src)
|
1070
1325
|
raise ValidationError, %Q[
|
1071
1326
|
Requested include folder: #{src} does not exist.
|
1072
1327
|
|
1073
1328
|
Specified include options: #{self.include_files_input}
|
1074
|
-
|
1329
|
+
|
1330
|
+
]
|
1075
1331
|
end
|
1076
1332
|
tgt_pathname = Pathname.new(tgt)
|
1077
1333
|
if tgt_pathname.absolute?
|
@@ -1081,7 +1337,8 @@ Only relative target path names are allowed.
|
|
1081
1337
|
Requested target folder: #{tgt} is an absolute file name.
|
1082
1338
|
|
1083
1339
|
Specified include options: #{self.include_files_input}"
|
1084
|
-
|
1340
|
+
|
1341
|
+
]
|
1085
1342
|
end
|
1086
1343
|
if /\.\./.match(tgt)
|
1087
1344
|
raise ValidationError, %Q[
|
@@ -1090,10 +1347,12 @@ Only expanded relative target paths are allowed.
|
|
1090
1347
|
Requested target folder includes '..'.
|
1091
1348
|
|
1092
1349
|
Specified include options: #{self.include_files_input}"
|
1093
|
-
|
1350
|
+
|
1351
|
+
]
|
1094
1352
|
end
|
1095
1353
|
end
|
1096
1354
|
|
1355
|
+
# TODO rename to verify_workspace!
|
1097
1356
|
def expect_features_directory_in_workspace
|
1098
1357
|
path = derived_workspace
|
1099
1358
|
features = File.join(path, "features")
|
@@ -1114,6 +1373,7 @@ You have two options:
|
|
1114
1373
|
See also
|
1115
1374
|
|
1116
1375
|
$ test-cloud help submit
|
1376
|
+
|
1117
1377
|
])
|
1118
1378
|
end
|
1119
1379
|
|
@@ -1134,7 +1394,7 @@ $ test-cloud help submit
|
|
1134
1394
|
end
|
1135
1395
|
|
1136
1396
|
def detect_workspace(options)
|
1137
|
-
options[
|
1397
|
+
options[:workspace] || File.expand_path(".")
|
1138
1398
|
end
|
1139
1399
|
|
1140
1400
|
def expect_workspace_directory(path)
|
@@ -1233,6 +1493,8 @@ Check your local Gemfile and and the remote Gemfile at:
|
|
1233
1493
|
$?.exitstatus == 0
|
1234
1494
|
end
|
1235
1495
|
|
1496
|
+
# TODO: Server detection algorithm might be broken.
|
1497
|
+
# https://github.com/xamarinhq/test-cloud-command-line/issues/19
|
1236
1498
|
def check_for_calabash_server(dir, app_dir)
|
1237
1499
|
if system("xcrun --find otool-classic &> /dev/null")
|
1238
1500
|
otool_cmd = "xcrun otool-classic"
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module XamarinTestCloud
|
2
2
|
|
3
3
|
# TODO validate dsym against the current application.
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
# 6. confirm that they match.
|
10
|
-
class Dsym
|
4
|
+
# https://github.com/xamarinhq/test-cloud-command-line/issues/91
|
5
|
+
#
|
6
|
+
# TODO dsym-file can be relative to workspace
|
7
|
+
# https://github.com/xamarinhq/test-cloud-command-line/issues/92
|
8
|
+
class Dsym
|
11
9
|
|
12
10
|
attr_reader :path
|
13
11
|
|
@@ -76,13 +76,13 @@ expanded: #{expanded}
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def remote_path
|
79
|
-
@remote_path ||=
|
79
|
+
@remote_path ||= begin
|
80
80
|
require "pathname"
|
81
81
|
absolute = Pathname.new(path)
|
82
82
|
root = Pathname.new(basedir)
|
83
83
|
relative = absolute.relative_path_from(root)
|
84
84
|
relative.to_s
|
85
|
-
end
|
85
|
+
end
|
86
86
|
end
|
87
87
|
|
88
88
|
private
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xamarin-test-cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Krukow
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-11-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -322,7 +322,6 @@ files:
|
|
322
322
|
- bin/test-cloud
|
323
323
|
- lib/xamarin-test-cloud/calabash_version_detector.rb
|
324
324
|
- lib/xamarin-test-cloud/cli.rb
|
325
|
-
- lib/xamarin-test-cloud/cli.rb alias
|
326
325
|
- lib/xamarin-test-cloud/dsym.rb
|
327
326
|
- lib/xamarin-test-cloud/environment.rb
|
328
327
|
- lib/xamarin-test-cloud/http/payload.rb
|
@@ -351,7 +350,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
351
350
|
version: '0'
|
352
351
|
requirements: []
|
353
352
|
rubyforge_project:
|
354
|
-
rubygems_version: 2.
|
353
|
+
rubygems_version: 2.5.1
|
355
354
|
signing_key:
|
356
355
|
specification_version: 4
|
357
356
|
summary: Command-line interface to Xamarin Test Cloud
|
Binary file
|