xamarin-test-cloud 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f60e55bbba9205215510389613c5c60672d9983
4
- data.tar.gz: 237e950267809c66173d8d388593a5b598865c63
3
+ metadata.gz: 7179d836cc88e3266185b3d9cd68afa6b8272681
4
+ data.tar.gz: 50bb75d45e930271faaa5a28ae6f718895790a6d
5
5
  SHA512:
6
- metadata.gz: c5696ca55bd8e3c6fde7043b000ffc8dd97d4bab99aa7f5a5e2aa4a7f8bdb52bbd7a64e31a7ea0443aaebb59bb1f8a6938e2a2901fc6c0ce680a647ee4b67390
7
- data.tar.gz: a93037446d255ead1f82a3397fcf6cc879091d28cec34378ef03c3e95776478218e3b5053a6719d331142fd528c843e3ef2245e1e661069c6e6a7b726e136aa2
6
+ metadata.gz: 2adca474985c4505d9dbe98b5ae5c0e0da1365d921578328f2a3a21a7f13d84fdc8ef07e405cb638b8042bb3543602b49b642bac55117bc37fb9c796d5ed9573
7
+ data.tar.gz: 2ed5fcd3105e9622d69c1e88318b4c64bf4fced3bc516877c7cc6804385739f46337fe7acafba81e2f80a0fb2681b8531b09f7d35d6eda65c1f9f739bde642f9
@@ -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
- attr_writer :included_files_map
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
- app_path = File.expand_path(app)
192
- unless File.exist?(app_path)
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
- # TODO: extract this method and the configuration branch below to a module
241
- parse_and_set_config_and_profile
242
- unless self.skip_config_check
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 = #{self.included_files_map}" if self.included_files_map
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
- File.file?(path)
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
- self.included_files_map.each_pair do |src, dest|
832
- FileUtils.cp_r(src, File.join(tmpdir,dest))
833
- collect_files_with_glob(File.join(tmpdir,dest,"**","*")).map do |file|
834
- collected_files << TestFile.new(file, tmpdir)
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? { |x| x[:filename] == filename.sub("libmonodroid.so", "libmonosgen-2.0.so") }
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
- if !config_path
1010
- self.config = false
1011
- return
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
- if config_path
1015
- config_path = File.expand_path(config_path)
1016
- unless File.exist?(config_path)
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
- begin
1021
- config_yml = YAML.load(ERB.new(File.read(config_path)).result)
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
- if Environment.debug?
1028
- puts 'Parsed Cucumber config as:'
1029
- puts config_yml.inspect
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
- profile = options[:profile]
1033
- unless profile
1034
- raise ValidationError, 'Config file provided but no profile selected.'
1226
+ if profile
1227
+ expect_profile_exists_in_cucumber_config(config_path, profile)
1228
+ @profile = profile
1035
1229
  else
1036
- unless config_yml[profile]
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
- self.config = TestFile.cucumber_config(config_path)
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
- parsed_included_folders = {}
1060
- self.include_files_input.each do |folder|
1061
- src = File.join(basedir, folder)
1062
- validate_include_folder!(src, folder)
1063
- parsed_included_folders[src]=folder
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
- parsed_included_folders
1320
+ source_target_map
1066
1321
  end
1067
1322
 
1068
- def validate_include_folder!(src, tgt)
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["workspace"] || File.expand_path(".")
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
- # 1. put the dSYM.zip and .ipa in a directory
5
- # 2. $ unzip <the>.ipa
6
- # 3. $ unzip <the>.dSYM.zip
7
- # 4. $ xcrun dwarfdump --uuid Payload/My.app/My
8
- # 5. $ xcrun dwarfdump --uuid My.app.dSYM
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 ||= lambda do
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.call
85
+ end
86
86
  end
87
87
 
88
88
  private
@@ -1,3 +1,3 @@
1
1
  module XamarinTestCloud
2
- VERSION = "2.0.3"
2
+ VERSION = "2.1.0"
3
3
  end
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.3
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-10-28 00:00:00.000000000 Z
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.6.4
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