fwtoolkit 0.9.3 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +8 -8
  2. data/bin/fwt +2 -112
  3. data/features/cocoapods/setup.feature +60 -0
  4. data/features/frank/model.feature +20 -0
  5. data/features/frank/setup.feature +28 -0
  6. data/features/git/create.feature +29 -0
  7. data/features/project/create.feature +25 -0
  8. data/features/step_definitions/aruba_steps.rb +11 -0
  9. data/features/step_definitions/git_steps.rb +30 -0
  10. data/features/step_definitions/project_steps.rb +50 -0
  11. data/features/step_definitions/rvm_steps.rb +11 -0
  12. data/features/step_definitions/system_steps.rb +8 -0
  13. data/features/support/env.rb +23 -0
  14. data/features/support/lib_test/aruba_fwt.rb +30 -0
  15. data/features/support/lib_test/aruba_mod.rb +28 -0
  16. data/features/support/lib_test/fake_gem.rb +47 -0
  17. data/features/xcode/create.feature +42 -0
  18. data/lib/fwtoolkit/cli/bootstrap.rb +75 -0
  19. data/lib/fwtoolkit/cli/ci.rb +52 -0
  20. data/lib/fwtoolkit/cli/cocoapods.rb +73 -0
  21. data/lib/fwtoolkit/cli/ext/thor.rb +35 -0
  22. data/lib/fwtoolkit/cli/frank.rb +113 -0
  23. data/lib/fwtoolkit/cli/fw_actions/template_dir.rb +59 -0
  24. data/lib/fwtoolkit/cli/fw_actions.rb +2 -0
  25. data/lib/fwtoolkit/cli/git.rb +42 -0
  26. data/lib/fwtoolkit/cli/ota.rb +109 -0
  27. data/lib/fwtoolkit/cli/ota_client/hockeyapp_client.rb +70 -0
  28. data/lib/fwtoolkit/cli/project.rb +83 -0
  29. data/lib/fwtoolkit/cli/thorutils.rb +14 -0
  30. data/lib/fwtoolkit/cli/xcode.rb +105 -0
  31. data/lib/fwtoolkit/cli.rb +27 -36
  32. data/lib/fwtoolkit/config/config.sample +8 -0
  33. data/lib/fwtoolkit/config.rb +41 -0
  34. data/lib/fwtoolkit/configfile.rb +36 -0
  35. data/lib/fwtoolkit/executable/executable.rb +45 -0
  36. data/lib/fwtoolkit/executable.rb +1 -0
  37. data/lib/fwtoolkit/ext/gem.rb +9 -0
  38. data/lib/fwtoolkit/ext/hash_yaml.rb +17 -0
  39. data/lib/fwtoolkit/git_client/git_client.rb +225 -0
  40. data/lib/fwtoolkit/git_client.rb +1 -0
  41. data/lib/fwtoolkit/projectfile.rb +50 -0
  42. data/lib/fwtoolkit/rake/ext/rake.rb +7 -0
  43. data/lib/fwtoolkit/rake/tasks/ci.rb +25 -0
  44. data/lib/fwtoolkit/rake/tasks/config.rb +13 -0
  45. data/lib/fwtoolkit/rake/tasks/ota.rb +31 -0
  46. data/lib/fwtoolkit/rake/tasks/project.rb +28 -0
  47. data/lib/fwtoolkit/rake/tasks/test.rb +59 -0
  48. data/lib/fwtoolkit/rake/tasks/xcode.rb +69 -0
  49. data/lib/fwtoolkit/rake/tasks.rb +20 -0
  50. data/lib/fwtoolkit/version.rb +1 -1
  51. data/lib/fwtoolkit.rb +4 -7
  52. data/spec/git_client_spec.rb +316 -0
  53. data/spec/project_config_spec.rb +40 -0
  54. data/spec/rake/project.rb +28 -0
  55. data/spec/rake/test.rb +85 -0
  56. data/spec/rake/xcode.rb +66 -0
  57. data/spec/support/aruba-doubles-rspec.rb +21 -0
  58. data/spec/support/ctx_rake.rb +23 -0
  59. data/spec/support/double_helper.rb +13 -0
  60. data/spec/support/project_generator.rb +45 -0
  61. data/templates/default_project/frank/%project_name%/%target_name%/%class_prefix%AppDelegate+Frank.h.tt +15 -0
  62. data/templates/{cucumber/AppDelegate+Frank.m.erb → default_project/frank/%project_name%/%target_name%/%class_prefix%AppDelegate+Frank.m.tt} +25 -21
  63. data/templates/{cucumber → default_project/frank/%project_name%/Frank}/features/example.feature +0 -0
  64. data/templates/{cucumber → default_project/frank/%project_name%/Frank}/features/step_definitions/launch_steps.rb +0 -0
  65. data/templates/{cucumber → default_project/frank/%project_name%/Frank}/features/support/env.rb +0 -0
  66. data/templates/{cucumber → default_project/frank/%project_name%/Frank}/features/support/mimic.rb +0 -0
  67. data/templates/default_project/frank/~template_config.rb +11 -0
  68. data/templates/default_project/frank_seed_core_data/%project_name%/Frank/features/support/models/%class_name%.rb.tt +30 -0
  69. data/templates/default_project/frank_seed_support/%project_name%/Frank/features/support/models/factories.rb.tt +10 -0
  70. data/templates/{cucumber → default_project/frank_seed_support/%project_name%/Frank}/features/support/views/my_objects_json.erb +0 -0
  71. data/templates/{cucumber → default_project/frank_seed_support/%project_name%/Frank}/features/support/views/my_objects_xml.erb +0 -0
  72. data/templates/{fwt/gitignore.erb → default_project/git/.gitignore} +0 -0
  73. data/templates/{fwt/rvmrc.erb → default_project/rvm/.rvmrc.tt} +2 -2
  74. data/templates/default_project/rvm/Gemfile +4 -0
  75. data/templates/default_project/xcode/%project_name%/%project_name%.xcodeproj/project.pbxproj.tt +583 -0
  76. data/templates/default_project/xcode/%project_name%/%project_name%.xcodeproj/project.xcworkspace/contents.xcworkspacedata.tt +7 -0
  77. data/templates/default_project/xcode/%project_name%/%project_name%.xcodeproj/xcshareddata/xcschemes/%project_name%-Release.xcscheme.tt +105 -0
  78. data/templates/default_project/xcode/%project_name%/%project_name%.xcodeproj/xcshareddata/xcschemes/%project_name%-Testing.xcscheme.tt +105 -0
  79. data/templates/default_project/xcode/%project_name%/%project_name%.xcodeproj/xcshareddata/xcschemes/%project_name%.xcscheme.tt +105 -0
  80. data/templates/default_project/xcode/%project_name%/%target_name%/%class_prefix%AppDelegate.h.tt +15 -0
  81. data/templates/default_project/xcode/%project_name%/%target_name%/%class_prefix%AppDelegate.m.tt +49 -0
  82. data/templates/{fwt/default_project/Info.plist.erb → default_project/xcode/%project_name%/%target_name%/Supporting Files/%project_name%-Info.plist} +0 -0
  83. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/%project_name%-Prefix.pch.tt +14 -0
  84. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/Settings.bundle/Root.plist +53 -0
  85. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/Settings.bundle/en.lproj/Root.strings +0 -0
  86. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/en.lproj/InfoPlist.strings +2 -0
  87. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/fw-shared.xcconfig +49 -0
  88. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/info.plist.h.tt +8 -0
  89. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/main.m.tt +18 -0
  90. data/templates/default_project/xcode/%project_name%/%target_name%/Supporting Files/version.sh +159 -0
  91. data/templates/default_project/xcode/%project_name%/%tests_target_name%/%project_name%Tests.h.tt +13 -0
  92. data/templates/default_project/xcode/%project_name%/%tests_target_name%/%project_name%Tests.m.tt +32 -0
  93. data/templates/default_project/xcode/%project_name%/%tests_target_name%/Supporting Files/%tests_target_name%-Info.plist +22 -0
  94. data/templates/default_project/xcode/%project_name%/%tests_target_name%/Supporting Files/en.lproj/InfoPlist.strings +2 -0
  95. data/templates/default_project/xcode/%project_name%/Default.png +0 -0
  96. data/templates/default_project/xcode/%project_name%/Resources/Default-568h@2x.png +0 -0
  97. data/templates/default_project/xcode/%project_name%/Resources/Default.png +0 -0
  98. data/templates/default_project/xcode/%project_name%/Resources/Default@2x.png +0 -0
  99. data/templates/default_project/xcode/%project_name%.xcworkspace/contents.xcworkspacedata.tt +7 -0
  100. data/templates/default_project/xcode/FWProjectfile.tt +14 -0
  101. data/templates/default_project/xcode/Podfile.tt +4 -0
  102. data/templates/default_project/xcode/Rakefile.tt +14 -0
  103. data/templates/default_project/xcode/cruise_config.rb +3 -0
  104. data/templates/default_project/xcode/~template_config.rb +5 -0
  105. metadata +187 -141
  106. data/lib/fwtoolkit/tasks/build.rb +0 -121
  107. data/lib/fwtoolkit/tasks/ci.rb +0 -30
  108. data/lib/fwtoolkit/tasks/cocoapods.rb +0 -32
  109. data/lib/fwtoolkit/tasks/frank.rb +0 -119
  110. data/lib/fwtoolkit/tasks/helper.rb +0 -16
  111. data/lib/fwtoolkit/tasks/services.rb +0 -41
  112. data/lib/fwtoolkit/tasks.rb +0 -24
  113. data/lib/fwtoolkit/test/frank_model.rb +0 -120
  114. data/lib/fwtoolkit/test/misc_steps.rb +0 -9
  115. data/lib/fwtoolkit/test/model_helper.rb +0 -94
  116. data/lib/fwtoolkit/test/network_steps.rb +0 -60
  117. data/lib/fwtoolkit/test/pickle_steps.rb +0 -101
  118. data/lib/fwtoolkit/test/timeout_helper.rb +0 -21
  119. data/lib/fwtoolkit/test/ui_helper.rb +0 -19
  120. data/lib/fwtoolkit/test/ui_steps.rb +0 -17
  121. data/templates/cucumber/AppDelegate+Frank.h.erb +0 -15
  122. data/templates/fwt/Gemfile.erb +0 -3
  123. data/templates/fwt/Podfile.erb +0 -4
  124. data/templates/fwt/Rakefile.erb +0 -24
  125. data/templates/fwt/default_project/AppDelegate.h.erb +0 -12
  126. data/templates/fwt/default_project/AppDelegate.m.erb +0 -20
  127. data/templates/fwt/default_project/Prefix.pch.erb +0 -6
  128. data/templates/fwt/default_project/main.m.erb +0 -15
  129. data/templates/models/factories.rb.erb +0 -10
  130. data/templates/models/model.rb.erb +0 -30
@@ -0,0 +1,75 @@
1
+ require 'thor'
2
+ require 'fwtoolkit/config'
3
+ require 'fwtoolkit/cli/cocoapods'
4
+
5
+ module FWToolkit
6
+ class Bootstrap < Thor::Group
7
+ include Thor::Actions
8
+
9
+ def xcode_check
10
+ if File::exists?('/Applications/Xcode.app')
11
+ say_status :skip, 'Xcode is already installed', :blue
12
+ elsif
13
+ say_status :error, 'Xcode is not installed. Please download it from developer.apple.com', :red
14
+ end
15
+ end
16
+
17
+ def git_check
18
+ if File.available_in_path?('git')
19
+ say_status :skip, 'Git is already installed', :blue
20
+ elsif
21
+ say_status :error, 'Git is not installed. Please review your system configuration', :red
22
+ end
23
+ end
24
+
25
+ def rvm_check
26
+ if File.available_in_path?('rvm')
27
+ say_status :skip, 'Rvm is already installed', :blue
28
+ elsif
29
+ say_status :install, 'Installing rvm from https://get.rvm.io', :green
30
+ Dir.mktmpdir do |dir|
31
+ installer_path = File.join(dir, 'rvm_install.sh');
32
+ get 'https://get.rvm.io', installer_path
33
+ run! "bash -s stable #{installer_path}", {:capture => true}
34
+ end
35
+ end
36
+ end
37
+
38
+ def ruby_ver_check
39
+ default_rvm_ruby = run! 'rvm list default string', {:capture => true}
40
+ if default_rvm_ruby.include? Config.ruby_version
41
+ say_status :skip, "Ruby is already at the last version (#{Config.ruby_version})", :blue
42
+ end
43
+ say_status :install, "Installing ruby version #{Config.ruby_version} (through rvm)", :green
44
+ run! "rvm use --install #{Config.ruby_version}", {:with => 'bash -lc', :capture => true}
45
+ end
46
+
47
+ def cocoapods_check
48
+ if File.available_in_path?('pods')
49
+ say_status :skip, 'Cocoapods is already installed', :blue
50
+ elsif
51
+ invoke FWToolkit::Cocoapods, 'install', []
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ class File
58
+
59
+ def available_in_path?(prog_name)
60
+ which(prog_name)!=nil
61
+ end
62
+
63
+ private
64
+
65
+ def which cmd
66
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
67
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
68
+ exts.each do |ext|
69
+ exe = "#{path}/#{cmd}#{ext}"
70
+ return exe if File.executable? exe
71
+ end
72
+ end
73
+ return nil
74
+ end
75
+ end
@@ -0,0 +1,52 @@
1
+ require 'thor'
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'fwtoolkit/git_client'
5
+ require 'fwtoolkit/config'
6
+
7
+ module FWToolkit
8
+ class Ci < Thor
9
+ include Thor::Actions
10
+
11
+ desc 'add [PROJECT_NAME] [PROJECT_DIR]', 'Add a project to the CI environment'
12
+ def add(project_name, project_root)
13
+ raise Thor::Error, "\"#{project_root}\" doesn't contain a valid git repository" unless repository.initialized?
14
+
15
+ if project_exists_on_ci? project_name
16
+ say_status :skip, "There's already a project named \"#{project_name}\" on the ci at #{Config.ci_server_url}"
17
+ return
18
+ end
19
+
20
+ remotes = repository.remotes
21
+ raise Thor::Error, "\"#{project_root}\" is a local-only repository" if remotes.to_a.size == 0
22
+
23
+ remotes = repository.remotes
24
+ if remotes.keys.count == 1
25
+ remote_name = remotes.values.first
26
+ else
27
+ remote_name = ask 'There\'s more than one remote configured for this repository. Select one:', {:limited_to => remotes.keys }
28
+ end
29
+
30
+ remote_url = remotes[remote_name]
31
+
32
+ response = Net::HTTP.post_form(URI.parse("#{Config.ci_server_url}/projects"),
33
+ {'project[name]' => project_name,
34
+ 'project[source_control][repository]' => remote_url,
35
+ 'project[source_control][source_contro]' => 'Git',
36
+ 'project[source_control][branch]' => 'dev'})
37
+ if response.kind_of? Net::HTTPSuccess
38
+ say_status :add, "Project \"#{project_name}\" successfully added to the CI environment", :green
39
+ elsif
40
+ raise Thor::Error, "Failed to add project \"#{project_name}\" to the CI"
41
+ end
42
+
43
+ end
44
+
45
+ private
46
+ def project_exists_on_ci?(project_name)
47
+ response = Net::HTTP.request_get URI.parse("#{Config.ci_server_url}/builds/#{project_name}")
48
+ response.kind_if? Net::HTTPSuccess
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,73 @@
1
+ require 'thor'
2
+ require 'fwtoolkit/cli/ext/thor'
3
+ require 'fwtoolkit/ext/gem'
4
+
5
+ module FWToolkit
6
+ class Cocoapods < Thor
7
+ include Thor::Actions
8
+
9
+ desc 'setup', 'Install and configure cocoapods for the current user'
10
+ option :'skip-install', :desc => 'Skip cocoapods gem install and only configure the fw repository'
11
+ def setup
12
+ install_cocoapods_gem unless options[:'skip-install']
13
+ setup_cocoapods_repos
14
+ end
15
+
16
+ desc 'install [PROJECT_DIR]', 'Installs pods for the project at project_dir'
17
+ def install(project_root)
18
+ add_cocoapods_to_project project_root
19
+ if File.exists? File.join(project_root, 'Podfile')
20
+ inside(project_root) { run! 'bundle exec pod install', :capture => true }
21
+ else
22
+ say_status :skip, "Unable to locate the Podfile. Skipping pod install", :blue
23
+ end
24
+ end
25
+
26
+
27
+ private
28
+
29
+ def install_cocoapods_gem
30
+ if inside(ENV['HOME']) {Gem::gem_available? 'cocoapods'}
31
+ say_status :skip, 'Cocoapods is already installed', :blue
32
+ else
33
+ say_status :install, 'Installing cocoapods gem system-wise (requires root password)', :green
34
+ run! 'sudo gem install cocoapods', {:capture => true}
35
+ end
36
+ end
37
+
38
+ def setup_cocoapods_repos
39
+ # I'm avoiding calling cocoapods directly in order not to need them as a dependecy for this set of commands
40
+ say_status :warning, 'Cocoapods doesn\'t seem to be installed in your system. Please run fwt pods setup', :yellow if !Gem::gem_available?('cocoapods')
41
+ fw_repo_path = File.join(ENV['CP_REPOS_DIR'] || "~/.cocoapods", 'fw')
42
+ if Dir.exists? fw_repo_path
43
+ say_status :skip, 'FW\'s podspec repository already installed', :blue
44
+ else
45
+ say_status :configure, 'Configuring FW\'s podspec repository', :green
46
+ FileUtils.mkdir_p fw_repo_path
47
+ inside(fw_repo_path) { run! 'git clone git@github.com:FutureWorkshops/FWTPodspecs.git .', :capture => true }
48
+ end
49
+ end
50
+
51
+ def add_cocoapods_to_project(project_root)
52
+ gemfile = File.join(project_root, 'Gemfile')
53
+ raise Thor::Error, "Can't locate a valid Gemfile at path: #{File.expand_path project_root}" unless File.exist?(gemfile)
54
+
55
+ unless cocoapods_in_gemfile? gemfile
56
+ say_status :add, 'Add cocoapods to the Gemfile', :blue
57
+ File.open(gemfile, "a") { |f| f.write 'gem "Cocoapods"' }
58
+ run! 'bundle', :capture => true
59
+ end
60
+ end
61
+
62
+ def cocoapods_in_gemfile?(gemfile_path)
63
+ File.read(gemfile_path).split("\n").select{ |line| line =~ /gem .Cocoapods./ }.count == 0
64
+ end
65
+
66
+ # def gemfile_gems_installed?(project_root)
67
+ # inside(project_root) do
68
+ # system('bundle check')
69
+ # $?.success?
70
+ # end
71
+ # end
72
+ end
73
+ end
@@ -0,0 +1,35 @@
1
+ require 'thor'
2
+
3
+ class Thor
4
+ module Actions
5
+ alias_method :run_base, :run
6
+ def run(command, config={})
7
+ command_output = run_base(command, config)
8
+ if config[:raise_errors] && !$?.success?
9
+ command_output.gsub!(/e\[\d+m/, '') #Stripping colors
10
+ say "An error has occured while running: \"#{command}\"", :red
11
+ say 'Command output:'
12
+ raise Thor::Error, "\n***\n#{command_output}***"
13
+ end
14
+ end
15
+
16
+ def run!(command, config={})
17
+ config.merge!({ :raise_errors => true })
18
+ run command, config
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ class Thor
25
+ module Actions
26
+ class EmptyDirectory
27
+ protected
28
+ def convert_encoded_instructions(filename)
29
+ filename.gsub(/%(.*?)%/) do |initial_string|
30
+ config[$1.strip.to_sym] or call_public_method($1.strip) or initial_string
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,113 @@
1
+ require 'thor'
2
+ require 'xcodeproj'
3
+ require 'core_data'
4
+ require 'fwtoolkit/ext/gem'
5
+ require 'fwtoolkit/projectfile'
6
+ require 'fwtoolkit/cli/fw_actions'
7
+ require 'fwtoolkit/cli/thorutils'
8
+
9
+ module Xcodeproj
10
+ class Project
11
+ def core_data_files(target_name=nil)
12
+ mom_files = Array.new
13
+ targets_list = target_name ? self.targets.select { |t| t.name == target_name } : self.targets
14
+ targets_list.each do |t|
15
+ mom_files << t.source_build_phase.files.select{ |f| f.display_name =~ /.*?\.xcdatamodeld/ }.map{ |f| f.file_ref.current_version.path }
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ class String
22
+ def ruby_format
23
+ self.gsub(/(.)([A-Z])/,'\1_\2').downcase
24
+ end
25
+
26
+ def ruby_format!
27
+ replace ruby_format
28
+ end
29
+ end
30
+
31
+ module FWToolkit
32
+ class Frank < Thor
33
+ include Thor::Actions
34
+ include FWToolkit::ThorUtils
35
+ source_root_templates!
36
+
37
+ add_runtime_options!
38
+
39
+ desc 'setup [PROJECT_DIR]', 'Sets up Frank for the project at project_dir and on the given target'
40
+ option :target,
41
+ :banner => 'Xcode target',
42
+ :desc => 'Specify the build target that Frank should use. Default: the one specified by :target in the FWProjectFile'
43
+ def setup(project_dir)
44
+ destination_root = project_dir
45
+ Projectfile.load!(project_dir)
46
+
47
+ if !options[:force] && frank_alredy_set_up?(project_dir)
48
+ say_status :skip, 'Frank is already set up for the project'
49
+ return
50
+ end
51
+ say 'Setting up Frank'
52
+
53
+ template_conf = Projectfile.config
54
+ Projectfile.config[:target_name] ||= options[:target] if options[:target]
55
+
56
+ inside(File.join(destination_root, template_conf[:project_name])) { run! "frank setup --target #{Projectfile.target_name}" }
57
+
58
+ #remove files we're going to overwrite
59
+ FileUtils.rm File.join(destination_root, template_conf[:project_name], 'Frank', 'features', 'step_definitions', 'launch_steps.rb')
60
+ FileUtils.rm File.join(destination_root, template_conf[:project_name], 'Frank', 'features', 'support', 'env.rb')
61
+
62
+ template_directory 'templates/default_project/frank', destination_root, template_conf
63
+ end
64
+
65
+ desc 'model [PROJECT_DIR]', 'Creates Frank model files from CoreData for the project at project_dir'
66
+ option :modelfile,
67
+ :banner => 'core data xcdatamodel file',
68
+ :desc => 'Specify the position of the xcdatamodel file you want to extract the Core Data entity from. By default, fwtoolkit searches recursively inside project_dir for all *.xcdatamodel files'
69
+ def model(project_dir)
70
+ say 'Creating model files out of core data entities'
71
+ destination_root = project_dir
72
+ Projectfile.load!(project_dir)
73
+
74
+ if options[:modelfile].nil?
75
+ mom_files = Dir.glob(File.join(project_dir, '**/*.xcdatamodel'))
76
+
77
+ if mom_files.size > 1
78
+ mom_file = ask('I\'ve found more than one core data model, which one would you like to use?', mom_files)
79
+ elsif mom_files.size == 1
80
+ mom_file = mom_files[0]
81
+ else
82
+ raise Thor::Error, "Can't locate a valid core data model for #{mom_file}"
83
+ end
84
+ end
85
+
86
+ template_conf = Projectfile.config
87
+
88
+ model = CoreData::DataModel.new File.join(mom_file, 'contents')
89
+
90
+ model.entities.each do |entity|
91
+ seed_conf = template_conf.clone
92
+ seed_conf[:class_name] = remove_prefix(template_conf[:class_prefix], entity.name).ruby_format
93
+ seed_conf[:model] = entity
94
+ directory 'templates/default_project/frank_seed_core_data', destination_root, seed_conf
95
+ end
96
+
97
+ template_conf[:models] = model.entities
98
+ directory 'templates/default_project/frank_seed_support', destination_root, template_conf
99
+ end
100
+
101
+ private
102
+
103
+ def remove_prefix(prefix, entity)
104
+ entity[/^#{prefix}/] = '' if entity[/^#{prefix}/]
105
+ entity
106
+ end
107
+
108
+ def frank_alredy_set_up?(project_dir)
109
+ File.exists? File.join(project_dir, File.basename(project_dir), 'Frank')
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,59 @@
1
+ require 'thor'
2
+ require 'thor/actions'
3
+ require 'fileutils'
4
+ require 'singleton'
5
+
6
+ class Thor
7
+ module Actions
8
+ def template_directory(source, *args, &block)
9
+ config = args.last.is_a?(Hash) ? args.pop : {}
10
+ destination = args.first || source
11
+ action TemplateDirectory.new(self, source, destination || source, config, &block)
12
+ end
13
+
14
+ class TemplateDirectory < Directory
15
+
16
+ module DSL
17
+ class Support
18
+ include Thor::Actions
19
+ include Singleton
20
+ def initialize
21
+ super nil, options, config
22
+ end
23
+ end
24
+ def project_config
25
+ yield(Thor::Util.escape_globs(destination), config)
26
+ end
27
+
28
+ def support
29
+ Support.instance
30
+ end
31
+ end
32
+
33
+ include DSL
34
+
35
+ protected
36
+ def execute!
37
+ super
38
+
39
+ lookup = Thor::Util.escape_globs(destination)
40
+ lookup = file_level_lookup(lookup)
41
+
42
+ files(lookup).select{|f| f =~ /~template_config.rb/ }.each do |file_source|
43
+ conf = File.open(file_source, 'r:utf-8') { |f| f.read }
44
+ # Work around for Rubinius incomplete encoding in 1.9 mode
45
+ if conf.respond_to?(:encoding) && conf.encoding.name != "UTF-8"
46
+ conf.encode!('UTF-8')
47
+ end
48
+ base.shell.say_status :executing, "configuration file: #{base.relative_to_original_destination_root(file_source)}", :green
49
+ begin
50
+ eval(conf, binding, file_source)
51
+ FileUtils.rm file_source
52
+ rescue Exception => e
53
+ raise Thor::Error, "Invalid `#{file_source}` file: #{e.message}", e.backtrace
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,2 @@
1
+ require 'thor'
2
+ require 'fwtoolkit/cli/fw_actions/template_dir'
@@ -0,0 +1,42 @@
1
+ require 'thor'
2
+ require 'fwtoolkit/cli/fw_actions'
3
+ require 'fwtoolkit/git_client'
4
+ require 'fwtoolkit/cli/thorutils'
5
+
6
+ module FWToolkit
7
+ class Git < Thor
8
+ include Thor::Actions
9
+ include FWToolkit::ThorUtils
10
+
11
+ source_root_templates!
12
+
13
+ desc 'new', 'Creates a git repository and commits to master all the files in project_dir'
14
+ def new(project_root)
15
+ destination_root = project_root
16
+ repository = GitClient::Repository.new(project_root)
17
+ raise Thor::Error, "There's already a repository at path: \"#{project_root}\"" if repository.initialized?
18
+
19
+ template_directory 'templates/default_project/git', destination_root
20
+ begin
21
+ repository.init
22
+ repository.add_files_to_index
23
+ repository.commit('First commit')
24
+ rescue GitClient::GitError => e
25
+ raise Thor::Error, e.message + "\n#{e.git_output}"
26
+ end
27
+
28
+ end
29
+
30
+ desc 'update', 'Updates submodules for the repository in project_dir'
31
+ def update(project_root)
32
+ repository = GitClient::Repository.new(project_root)
33
+ raise Thor::Error, "There's no initialized repository at path: #{project_root}" unless git_repo.initialized?
34
+
35
+ begin
36
+ repository.submodule_update :init => true
37
+ rescue GitError => e
38
+ raise Thor::Error, e.message + "\n#{e.git_output}"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,109 @@
1
+ require 'thor'
2
+ require 'rake'
3
+ require 'fwtoolkit/projectfile'
4
+ require 'fwtoolkit/xcode'
5
+ require 'fwtoolkit/config'
6
+ require 'fwtoolkit/hockeyapp_client'
7
+ require 'fwtoolkit/hash_yaml'
8
+
9
+ module XcodedBuild
10
+ def self.create_ipa(xcarchive_path, ipa_output, dev_id=nil, provisionin_profile=nil)
11
+ provisioning_profile = File.expand_path provisioning_profile
12
+ raise Thor::Error, "Unable to locate the provisioning profile: #{provisioning_profile}" unless File.exists?(provisioning_profile)
13
+
14
+ app_path = find_unique! xcarchive_path, '*.app'
15
+ raise Thor::Error, "Unable to find any .app file at path: #{xcarchive_path}" unless app_path
16
+
17
+ ipa_output = File.expand_path ipa_output
18
+
19
+ cmd_line = "xcrun -sdk iphoneos PackageApplication -v #{app_path} -o #{ipa_output}"
20
+ cmd_line += "--sign #{dev_id}" if dev_id
21
+ cmd_line += "--embed #{provisioning_profile}" if provisioning_profile
22
+ run! "xcrun -sdk iphoneos PackageApplication -v #{app_path} -o #{ipa_output}"
23
+ end
24
+
25
+ def self.find_unique!(root, file)
26
+ files_in_root = Dir["#{root}/**/#{file}"]
27
+ raise Thor::Error, "Found more than one \"#{file}\" at path: #{root}" if apps_in_root.size > 1
28
+ files_in_root.size > 0 ? File.expand_path(files_in_root.first) : nil
29
+ end
30
+ end
31
+
32
+ module FWToolkit
33
+ class Ota < Thor
34
+ include Thor::Actions
35
+
36
+ desc 'ipa [PROJECT_ROOT]', 'Creates an ipa file signed with the credentials defined in the FWProjectfile for the project at project_root'
37
+ option :sign,
38
+ :type => :boolean,
39
+ :default => :true,
40
+ :desc => 'If true, the dev_id defined in the project file is ignored and the app is signed with the dev_id defined on FWProjectfile. Default: true'
41
+ def sign(project_root)
42
+ invoke FWToolkit::Xcode, 'build', [project_root], :clean => true, :archive => true, :type => 'testing', :sdk => 'iphoneos'
43
+ Projectfile.load! project_root
44
+
45
+ if options[:sign]
46
+ XcodeBuild.create_ipa xcarchive_path, ipa_path, Projectfile.dev_id, Projectfile.provisioning_profile
47
+ else
48
+ XcodeBuild.create_ipa xcarchive_path, ipa_path
49
+ end
50
+
51
+ say_status :created, "IPA at: #{ipa_path} signed with developer id: #{dev_id}", :green
52
+ end
53
+
54
+ desc 'upload [PROJECT_ROOT]', 'Upload a new build to FW\'s Hockeyapp account'
55
+ option :sign,
56
+ :type => :boolean,
57
+ :default => true,
58
+ :desc => 'If true, the dev_id defined in the project file is ignored and the app is signed with the dev_id defined on FWProjectfile. Default: true'
59
+ def upload(project_root)
60
+ if options[:sign]
61
+ invoke('sign')
62
+ else
63
+ invoke FWToolkit::Xcode, 'build', [project_root], :clean => true, :archive => true, :type => 'testing', :sdk => 'iphoneos'
64
+ end
65
+
66
+ Projectfile.load! project_root
67
+
68
+ raise Thor::Error, "Unable to find the xcarchive file at path: #{ipa}" unless File.exists?(ipa_path)
69
+ raise Thor::Error, "Unable to find the dSYM file at path: #{dsym}" unless File.exists?(dsym_path)
70
+
71
+ uploader = FWToolkit::OTA::HockeyappClient.new(Config.hockeyapp_api_token, Projectfile.app_token)
72
+
73
+ begin
74
+ uploader.upload_build ipa_path, dsym_path
75
+ rescue StandardError => e
76
+ say_status :error, "Error uploading to hockeyapp: #{e.message}", :red
77
+ end
78
+
79
+ say_status :upload, "Uploaded a new version to Hockeyapp", :green
80
+ end
81
+
82
+
83
+ private
84
+
85
+ def ipa_path
86
+ File.join xcarchive_path, "#{Projectfile.project_name}.ipa"
87
+ end
88
+
89
+ def dsym_path
90
+ File.join xcarchive_path, 'dSYMs' "#{Projectfile.project_name}.app.dSYM"
91
+ end
92
+
93
+ def artifacts_dir
94
+ File.join Config.artifacts_tmp_dir, Projectfile.project_name
95
+ end
96
+
97
+ def xcarchive_path
98
+ if @xcarchive_path.nil
99
+ build_conf = Hash.hash_from_yaml File.join(Config.artifacts_tmp_dir, Projectfile.project_name, 'env.log')
100
+
101
+ @xcarchive_path = build_conf[:ARCHIVE_PATH]
102
+ raise Thor::Error, "Cannot locate the xcarchive for the project" unless File.exists?(xcarchive)
103
+ end
104
+ @xcarchive_path
105
+ end
106
+
107
+
108
+ end
109
+ end
@@ -0,0 +1,70 @@
1
+ require 'hockeyapp'
2
+ require 'fwtoolkit/config'
3
+ require 'rubyzip'
4
+
5
+ module FWToolkit
6
+ module OTA
7
+ class HockeyappClient
8
+
9
+ class CmdUploader
10
+ def initialize(api_token, app_id)
11
+ HockeyApp::Config.configure { |config| config.token = api_token }
12
+ @client = HockeyApp.build_client
13
+ @app = HockeyApp::App.from_hash({"public_identifier" => app_id}, @client)
14
+ end
15
+
16
+ def upload_build(bin_file, dsym_file = nil, notes = nil)
17
+ raise ArgumentError, "No valid ipa file exists at path #{bin_file}" unless bin_file.exists?
18
+ raise ArgumentError, "No valid dsym_file file exists at path #{dsym_file}" unless (dsym_file.nil? || dsym_file.exists?)
19
+ zip_dsym = zipped_dsym(dsym_file) if dsym_file
20
+ new_version = HockeyApp::Version.new(@app, @client)
21
+ new_version.ipa = bin_file
22
+ new_version.dsym = zipped_dsym(zip_dsym)
23
+ new_version.notes = notes
24
+ @client.post_new_version new_version
25
+ end
26
+
27
+ def dsym_path_from_xcarchive(xcarchive_path)
28
+
29
+ end
30
+
31
+ def
32
+ end
33
+
34
+ # class GuiUploader
35
+ # def initialize(api_token, app_id)
36
+ # @api_token = api_token
37
+ # @app_id = app_id
38
+ # end
39
+
40
+ # def upload_build(bin_file, dsym_file = nil, notes = nil)
41
+ # raise ArgumentError, 'Not implemented'
42
+ # end
43
+ # end
44
+
45
+ # There are two kind of uploader: internal and gui. The second one utilizes hockeyapp's mac app to provide
46
+ def initialize(api_token, app_id, uploader=:cmd_uploader)
47
+ @uploader = uploader==:cmd_uploader ? CmdUploader.new(api_token, app_id) : GuiUploader.new(api_token, app_id)
48
+ end
49
+
50
+ def upload_build(bin_file, dsym_file = nil, notes = nil)
51
+ @uploader.upload_build bin_file, dsym_file, notes
52
+ raise ArgumentError, "No valid ipa file exists at path #{bin_file}" unless bin_file.exists?
53
+ raise ArgumentError, "No valid dsym_file file exists at path #{dsym_file}" unless (dsym_file.nil? || dsym_file.exists?)
54
+ zip_dsym = zipped_dsym(dsym_file) if dsym_file
55
+ new_version = HockeyApp::Version.new(@app, @client)
56
+ new_version.ipa = bin_file
57
+ new_version.dsym = zipped_dsym(zip_dsym)
58
+ new_version.notes = notes
59
+ @client.post_new_version new_version
60
+ end
61
+
62
+ def zipped_dsym(dsym_file)
63
+ zip_file = "#{dsym_file}.zip"
64
+ Zip::ZipFile.open(zip_file, Zip::ZipFile::CREATE) do |zipfile|
65
+ zipfile.add(dsym_file)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end