fwtoolkit 0.9.3 → 1.0.1

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 (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,83 @@
1
+ require 'thor'
2
+ require 'fwtoolkit/cli/xcode'
3
+ require 'fwtoolkit/cli/cocoapods'
4
+ require 'fwtoolkit/cli/git'
5
+ require 'fwtoolkit/projectfile'
6
+ require 'fwtoolkit/git_client'
7
+ require 'fwtoolkit/cli/thorutils'
8
+
9
+ module FWToolkit
10
+ class Project < Thor
11
+ include Thor::Actions
12
+
13
+ include FWToolkit::ThorUtils
14
+ source_root_templates!
15
+
16
+ desc "new [PROJECT NAME] [CLASS PREFIX]", "Create a new Xcode project with FW's settings"
17
+ def new(project_name, class_prefix)
18
+ destination_root = File.join(Dir.pwd, project_name)
19
+
20
+ say "Creating new project in: #{File.expand_path destination_root}"
21
+
22
+ invoke :conf_rvm, [destination_root]
23
+
24
+ invoke FWToolkit::Xcode, 'new', [project_name, class_prefix.upcase, File.join(Dir.pwd, project_name)]
25
+
26
+ #invoke FWToolkit::Cocoapods, 'setup', [] #needs empty arg list or it will propagate father'
27
+ invoke FWToolkit::Cocoapods, 'install', [destination_root]
28
+
29
+ #invoke FWToolkit::Frank, 'setup', [destination_root, project_name, class_prefix.upcase]
30
+
31
+ git_repo = GitClient::Repository.new destination_root
32
+ # gitignore is included on xcode new.. for now
33
+
34
+ if(git_repo.initialized?)
35
+ say_status :skip, 'The git repository is already initialized', :yellow
36
+ else
37
+ invoke FWToolkit::Git, 'new', [destination_root]
38
+ end
39
+ end
40
+
41
+ desc "conf_rvm [PROJECT_DIR]", "Configure rvm/gem environment on a project's folder"
42
+ def conf_rvm(project_root=Dir.pwd)
43
+ @project_name = File.basename(project_root)
44
+ @ruby_version = Config.ruby_version
45
+ destination_root = project_root
46
+
47
+ say 'Configuring rvm'
48
+
49
+ directory 'templates/default_project/rvm', destination_root
50
+
51
+ inside(destination_root) do
52
+ run! "rvm #{Config.ruby_version} do rvm --rvmrc --create ruby-#{Config.ruby_version}@#{@project_name}", {:capture => true}
53
+ bundle_update
54
+ end
55
+ end
56
+
57
+ desc "update [PROJECT_DIR]", "Update project's pods/gems and submodules"
58
+ def update(project_root=Dir.pwd)
59
+ bundle_update
60
+
61
+ invoke FWToolkit::Git, 'update', [project_root]
62
+ invoke FWToolkit::Cocoapods, 'install', [project_root]
63
+
64
+ end
65
+
66
+ private
67
+
68
+ def bundle_update
69
+ if File.exists? 'Gemfile'
70
+ begin
71
+ retried ||= false
72
+ run! 'bundle'
73
+ rescue Thor::Error
74
+ run! 'gem install bundler'
75
+ retried = true
76
+ retry unless retried
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,14 @@
1
+ module FWToolkit
2
+ module ThorUtils
3
+
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def source_root_templates!
10
+ source_root File.join(File.dirname(__FILE__), '..', '..', '..')
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,105 @@
1
+ require 'thor'
2
+ require 'fileutils'
3
+ require 'fwtoolkit/config'
4
+ require 'fwtoolkit/projectfile'
5
+ require 'fwtoolkit/cli/fw_actions'
6
+ require 'fwtoolkit/cli/thorutils'
7
+ require 'xcodebuild'
8
+
9
+ # This little hack is necesary to use XcodeBuild outside the context of rake
10
+ module XcodeBuild
11
+ module Tasks
12
+ class BuildTask
13
+ def define; end
14
+
15
+ def build!; xcodebuild :build end
16
+ def archive!; xcodebuild :archive end
17
+ def clean!; xcodebuild :clean end
18
+ end
19
+ end
20
+ end
21
+
22
+ module FWToolkit
23
+ class Xcode < Thor
24
+ include Thor::Actions
25
+ include FWToolkit::ThorUtils
26
+ source_root_templates!
27
+
28
+ desc "new [PROJECT_NAME] [CLASS_PREFIX]", "Create a new Xcode project with FW's settings"
29
+ def new(project_name, class_prefix, root_dir=File.join(Dir.pwd, project_name))
30
+ say 'Creating Xcode project'
31
+ destination_root = root_dir
32
+
33
+ #raise Thor::Error, "Can't create the project. The directory #{destination_root} already exists" if Dir.exist?(destination_root)
34
+
35
+ Projectfile.load_with_config! :project_name => project_name, :class_prefix => class_prefix.upcase
36
+
37
+ template_config = { :target_platform => Config.target_platform,
38
+ :organization_name => Config.organization_name,
39
+ :project_creator => Config.developer_name }
40
+ template_config.merge! Projectfile.config
41
+ template_directory 'templates/default_project/xcode', destination_root, template_config
42
+ end
43
+
44
+ desc "build [PROJECT_NAME]", "Compile a version of the Xcode project"
45
+ option :clean,
46
+ :type => :boolean,
47
+ :desc => 'Clean the project before building',
48
+ :default => true
49
+ option :archive,
50
+ :type => :boolean,
51
+ :desc => 'Archive the project after building',
52
+ :default => false
53
+ option :type,
54
+ :banner => 'type of build',
55
+ :desc => "The kind of build can be one of the following: dev, testing, release. Default: dev",
56
+ :default => 'dev'
57
+ option :sdk,
58
+ :banner => 'iphoneos/iphonesimulator',
59
+ :desc => "The platform to buy for: iphoneos or iphonesimulator. Default: iphoneos",
60
+ :default => 'iphoneos'
61
+ def build(project_dir)
62
+ build_types = ['dev', 'testing', 'release']
63
+ raise Thor::Error, 'Build type should be one of the following: dev, testing, release' unless build_types.include?(options[:type].downcase)
64
+
65
+ Projectfile.load! project_dir
66
+ output_dir = File.join artifacts_dir_for_project(Config.project_name), Projectfile.project_name
67
+ say_status :run, "Compiling the project and putting the output in: #{output_dir}", :blue
68
+
69
+ t = XcodeBuild::Tasks::BuildTask.new
70
+ t.invoke_from_within = 'project_dir'
71
+ t.sdk = options[:sdk]
72
+ t.workspace = Projectfile.xcode_workspace
73
+ t.scheme = Projectfile.xcode_scheme[options[:type].to_sym]
74
+ t.formatter = XcodeBuild::Formatters::ProgressFormatter.new
75
+ t.add_build_setting 'CONFIGURATION_BUILD_DIR', output_dir
76
+
77
+ if options[:clean]
78
+ FileUtils.rm_rf output_dir
79
+ t.clean!
80
+ end
81
+ options[:archive] ? t.archive! : t.build!
82
+ end
83
+
84
+
85
+ private
86
+ def artifacts_dir_for_project(project_name)
87
+ File.join Config.artifacts_tmp_dir, project_name
88
+ end
89
+ end
90
+ end
91
+
92
+ # :project_name -> OracleProject
93
+ # :binary_name -> OracleProject.app
94
+ # :class_prefix -> FWO
95
+ # :target_platform -> 6.0
96
+ # :provisioning
97
+ #
98
+ #binary_name -> app_name.app
99
+ #target_name -> app_name
100
+ #tests_target_name -> app_nameTests
101
+ #class_prefix -> XXX
102
+ #project_name -> app_name
103
+ #workspace_name -> app_name
104
+ #project_creator -> dev_name
105
+ #organization_name -> Future Workshops
data/lib/fwtoolkit/cli.rb CHANGED
@@ -1,40 +1,31 @@
1
- require 'fwtoolkit'
2
- require 'frank-cucumber/cli'
3
- require 'rake'
1
+ require 'thor'
2
+ require 'fwtoolkit/config'
3
+
4
+ require 'fwtoolkit/cli/ext/thor'
5
+ require 'fwtoolkit/cli/fw_actions'
6
+
7
+ require 'fwtoolkit/cli/cocoapods'
8
+ require 'fwtoolkit/cli/xcode'
9
+ require 'fwtoolkit/cli/project'
10
+ require 'fwtoolkit/cli/bootstrap'
11
+ require 'fwtoolkit/cli/ci'
12
+ require 'fwtoolkit/cli/frank'
13
+ require 'fwtoolkit/cli/git'
14
+ #require 'fwtoolkit/cli/ota'
4
15
 
5
16
  module FWToolkit
6
17
  class CLI < Thor
7
-
8
- include Rake::DSL
9
- include Thor::Actions
10
-
11
- desc "model CORE_DATA_MODEL", "create model files for cucumber"
12
- method_option :no_prefix, :aliases => "-np", :default => false, :type => :boolean
13
- def model(core_data_model_path)
14
- # validation step - core_data_model should be of type .xcdatamodel
15
- output_dir = File.join('Frank', 'features', 'support', 'models')
16
- FWToolkit::CLI.source_root(FWToolkit.root)
17
-
18
- @no_prefix = options.no_prefix
19
-
20
- model = CoreData::DataModel.new(File.join(core_data_model_path, 'contents'))
21
- @models = model.entities
22
-
23
- @models.each do |entity|
24
- @model = entity
25
- factory_template = File.join 'templates', 'models', 'model.rb.erb'
26
- template(factory_template, File.join(output_dir, "#{class_name(@model).ruby_format}.rb"))
27
- end
28
-
29
- factory_template = File.join 'templates', 'models', 'factories.rb.erb'
30
- template(factory_template, File.join(output_dir, 'factories.rb'))
31
- end
32
-
33
- no_tasks do
34
- def class_name(entity)
35
- @no_prefix ? entity.name : entity.name[3..-1]
36
- end
37
- end
18
+
19
+ register FWToolkit::Cocoapods, 'pods', 'pods SUBCOMMAND ...ARGS', 'Manage cocoapods'
20
+ register FWToolkit::Project, 'proj', 'proj SUBCOMMAND ...ARG', 'Create projects and manage settings'
21
+ register FWToolkit::Xcode, 'xcode', 'xcode SUBCOMMAND ...ARGS', 'Manage Xcode build process'
22
+ register FWToolkit::Bootstrap, 'bootstrap', 'bootstrap', 'Install and configure system tools'
23
+ register FWToolkit::Ci, 'ci', 'ci SUBCOMMAND ...ARGS', 'Manage the configuration of projects on the CI'
24
+ register FWToolkit::Frank, 'test', 'test SUBCOMMAND ...ARGS', 'Manage the testing framework'
25
+
26
+ register FWToolkit::Git, 'git', 'git SUBCOMMAND ...ARGS', 'Manage git flow'
27
+ #register FWToolkit::Ota, 'fwbuild', 'fwbuild SUBCOMMAND ...ARGS', 'Manage publishing build to the OTA server'
38
28
  end
39
-
40
- end
29
+ end
30
+
31
+ #
@@ -0,0 +1,8 @@
1
+ #developer_name: 'MANDATORY'
2
+
3
+ organization_name: 'Future Workshops'
4
+ ruby_version: '1.9.3'
5
+ target_platform: '6.0'
6
+ ci_server_url: 'http://ci.office.futureworkshops.com'
7
+
8
+ hockeyapp_api_token: # Create a token by going to hockeyapp.net
@@ -0,0 +1,41 @@
1
+ require 'fwtoolkit/configfile'
2
+ require 'fileutils'
3
+
4
+ module FWToolkit
5
+ module Config
6
+ include FWToolkit::ConfigFile
7
+
8
+ def self.config_file
9
+ File.join(ENV['HOME'], '.fwtoolkit', 'config')
10
+ end
11
+
12
+ def load!
13
+ unless File.exists? config_file
14
+ FileUtils.copy_file File.join(File.dirname(__FILE__), 'config', 'config.sample'), config_file
15
+ raise "Please configure fwtoolkit by editing the file at path: #{config_file}"
16
+ end
17
+
18
+ default_config = { :organization_name => 'Future Workshops',
19
+ :ruby_version => '1.9.3',
20
+ :target_platform => '6.0',
21
+ :ci_server_url => 'http://ci.office.futureworkshops.com',
22
+ :artifacts_tmp_dir => '/tmp/fwtoolkit/artifacts' }
23
+
24
+ load_config! config_file
25
+ end
26
+
27
+ def validate_config
28
+ unless @config.has_key?(:developer_name)
29
+ raise NameError, "Please configure fwtoolkit by editing the file at path: #{config_file}"
30
+ end
31
+ end
32
+
33
+ def conf_item_missing(name)
34
+ raise NoMethodError, "Please provide a valid '#{name}' by editing the conf file at path: #{config_file}"
35
+ end
36
+
37
+ extend self
38
+ end
39
+ end
40
+
41
+ FWToolkit::Config.load!
@@ -0,0 +1,36 @@
1
+ require 'fwtoolkit/ext/hash_yaml'
2
+
3
+ # Mixin module that reads a yaml file into a hash and responds to config values
4
+ module FWToolkit
5
+ module ConfigFile
6
+
7
+ attr_accessor :default_config
8
+
9
+ def config
10
+ @config ||= Hash.new
11
+ end
12
+
13
+ def load_config_hash!(config)
14
+ @config = config
15
+ merge_config @default_config if @default_config
16
+ validate_config if self.method_defined? :validate_config
17
+ end
18
+
19
+ def load_config!(config_file)
20
+ load_config_hash! Hash.hash_from_yaml(config_file)
21
+ end
22
+
23
+ def merge_config(default_config)
24
+ default_config.each { |key, value| config[key] ||= value }
25
+ end
26
+
27
+ def configure
28
+ yield config
29
+ end
30
+
31
+ def method_missing(name, *args, &block)
32
+ puts name
33
+ config[name.to_sym] || conf_item_missing(name) if self.method_defined? :conf_item_missing
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ module FWToolkit
2
+ module Executable
3
+
4
+ class ThorRunner
5
+ def run(command, config={})
6
+ Thor::Actions::run(command, config)
7
+ end
8
+
9
+ def report_error(command, command_output)
10
+ command_output.gsub!(/e\[\d+m/, '') #Stripping colors
11
+ say "An error has occured while running: \"#{command}\"", :red
12
+ say 'Command output:'
13
+ raise Thor::Error, "\n***\n#{command_output}***"
14
+ end
15
+ end
16
+
17
+ class CliRunner
18
+ def run(command, config={})
19
+ `#{command}`
20
+ end
21
+
22
+ def report_error(command, command_output)
23
+ command_output.gsub!(/e\[\d+m/, '')
24
+ puts "An error has occured while running: \"#{command}\"", :red
25
+ puts 'Command output:'
26
+ raise "\n***\n#{command_output}***"
27
+ end
28
+
29
+ end
30
+
31
+ def self.runner=(runner)
32
+ @@runner = runner
33
+ end
34
+
35
+ def run(command, options = {})
36
+ cmd_output = @@runner.run command, options
37
+ @@runner.report_error(command, cmd_output) if options[:raise_errors] && !$?.success?
38
+ end
39
+
40
+ def run!(command, options = {})
41
+ config.merge!({ :raise_errors => true })
42
+ run command config
43
+ end
44
+ end
45
+ end
@@ -0,0 +1 @@
1
+ require 'fwtoolkit/executable/executable.rb'
@@ -0,0 +1,9 @@
1
+ module Gem
2
+ def self.gem_available?(gem_name)
3
+ begin
4
+ Gem::Specification::find_by_name(gem_name)
5
+ rescue Gem::LoadError
6
+ false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ require 'yaml'
2
+
3
+ class Hash
4
+
5
+ def self.hash_from_yaml(yaml_file)
6
+ YAML::load_file(yaml_file).symbolize!
7
+ end
8
+
9
+ def symbolize!
10
+ keys.each do |k|
11
+ self[k.to_sym] = delete(k)
12
+ self[k.to_sym].symbolize! if self[k.to_sym].is_a? Hash
13
+ end
14
+ self
15
+ end
16
+ end
17
+
@@ -0,0 +1,225 @@
1
+
2
+ module GitClient
3
+ class GitError < StandardError
4
+ attr_reader :git_output
5
+
6
+ def initialize(git_output)
7
+ super
8
+ @git_output = git_output
9
+ end
10
+
11
+ def conflict?
12
+ git_output.any { |line| line.include? 'CONFLICT' }
13
+ end
14
+ end
15
+
16
+ class Repository
17
+ def initialize(repo_path)
18
+ @repo_root = repo_path
19
+ @git_folder = File.join(repo_path, '.git')
20
+ @merge = false
21
+ end
22
+
23
+ def initialized?
24
+ File.exists? @git_folder
25
+ end
26
+
27
+ def merging?
28
+ return @merge
29
+ end
30
+
31
+ def init
32
+ raise GitError.new("The folder #{@repo_root} already contains a git repository") if initialized?
33
+ git 'init'
34
+ end
35
+
36
+ def current_branch
37
+ current_branch = git('branch').split("\n").delete_if { |line| line[0] != "*" }
38
+ current_branch.first.gsub("* ", "")
39
+ end
40
+
41
+ def add_files_to_index(files=nil)
42
+ files = files ? files : '.'
43
+ files = files.is_a?(Array) ? files : [files]
44
+ files.each do |file|
45
+ git "add \"#{file}\""
46
+ end
47
+ end
48
+
49
+ def workdir_clean?
50
+ return status.empty?
51
+ end
52
+ # x index, y working_dir
53
+ # X Y Meaning
54
+ # -------------------------------------------------
55
+ # [MD] not updated
56
+ # M [ MD] updated in index
57
+ # A [ MD] added to index
58
+ # D [ M] deleted from index
59
+ # R [ MD] renamed in index
60
+ # C [ MD] copied in index
61
+ # [MARC] index and work tree matches
62
+ # [ MARC] M work tree changed since index
63
+ # [ MARC] D deleted in work tree
64
+ # -------------------------------------------------
65
+ # D D unmerged, both deleted
66
+ # A U unmerged, added by us
67
+ # U D unmerged, deleted by them
68
+ # U A unmerged, added by them
69
+ # D U unmerged, deleted by us
70
+ # A A unmerged, both added
71
+ # U U unmerged, both modified
72
+ # -------------------------------------------------
73
+ # ? ? untracked
74
+ # ! ! ignored
75
+ # -------------------------------------------------
76
+
77
+ def status
78
+ output = git 'status -s'
79
+ status_hash = Hash.new
80
+ return status_hash if output.length == 0 || merging?
81
+
82
+ output.split("\n").each do |entry|
83
+ raw_status = entry[0..1]
84
+ status = case raw_status ##needs to split leaving the freaking spaces on!
85
+ when / (M|D)/ then :idx_not_up_to_date
86
+ when /(A|M|R)M/ then :idx_not_up_to_date
87
+ when /A / then :idx_added
88
+ when /M / then :idx_modified
89
+ when /D / then :idx_deleted
90
+ when /R / then :idx_renamed
91
+ when /\?\?/ then :untracked
92
+ when /(DD|AA|(U|D|A)(U|D|A))/ then :merging
93
+ else :unknown
94
+ end
95
+
96
+ filename = entry.split(' ')[1]
97
+ status_hash[status] ||= []
98
+ status_hash[status] << filename
99
+ end
100
+ status_hash
101
+ end
102
+
103
+ def remotes
104
+ remotes = git 'remote -v'
105
+ remotes_hash = Hash.new
106
+ remotes.split("\n").each do |line|
107
+ split = line.split(' ')[0..1]
108
+ remotes_hash[symbolicate(split[0])] = split[1]
109
+ end if remotes
110
+ remotes_hash
111
+ end
112
+
113
+ def submodules
114
+ submodules_hash = Hash.new
115
+ return submodules_hash unless File.exists? File.join(@repo_root, '.gitmodules')
116
+
117
+ submodules = git "config -f .gitmodules --get-regexp '^submodule\..*\.path$'"
118
+ submodules.split("\n").each do |line|
119
+ split = line.split(' ')[0..1]
120
+ submodule_name = split[0][/^submodule.(.*).path$/, 1]
121
+ submodule_path = split[1]
122
+ submodule_remote = (git "config -f .gitmodules --get-all 'submodule.#{submodule_name}.url'").delete "\n"
123
+
124
+ submodules_hash[submodule_path] = submodule_remote
125
+ end
126
+ submodules_hash
127
+ end
128
+
129
+ def submodules_update(conf)
130
+ return if submodules.empty?
131
+ git "submodule init" if(conf[:init])
132
+ git "submodule update --recursive"
133
+ end
134
+
135
+ def branch_exist?(branch_name)
136
+ git('branch').split("\n").any? { |line| line.include? branch_name }
137
+ end
138
+
139
+ def ensure_branch_exists(branch_name)
140
+ return if branch_exist? branch_name
141
+ raise GitError, "Branch #{branch_name} doesn't exists"
142
+ end
143
+
144
+ def ensure_workdir_clean
145
+ return if workdir_clean?
146
+ raise GitError, 'The working directory is not clean'
147
+ end
148
+
149
+ # returns the commit hash
150
+ def commit(message)
151
+ output = git "commit -m\"#{message}\""
152
+ output[/\[\w* (\w*)\] .*/,1]
153
+ end
154
+
155
+ def switch_branch(branch_name, force_create=true)
156
+ ensure_branch_exists branch_name unless force_create
157
+
158
+ git "branch #{branch_name}" if force_create && !branch_exist?(branch_name)
159
+ git "checkout \"#{branch_name}\"" unless current_branch == branch_name
160
+ end
161
+
162
+ def merge(from_branch, into_branch=nil, msg=nil)
163
+ ensure_branch_exists from_branch
164
+ ensure_branch_exists into_branch if into_branch
165
+
166
+ ensure_workdir_clean
167
+ git "checkout \"#{into_branch}\""
168
+
169
+ begin
170
+ merge = true
171
+ msg.nil? ? git("merge --no-ff #{from_branch}"): git("merge --no-ff #{from_branch} -m \"#{msg}\"")
172
+ rescue GitError => e
173
+ git 'merge --abort' if e.conflict?
174
+ merge = false
175
+ raise e
176
+ end
177
+ end
178
+
179
+ def save_stash
180
+ git 'stash save'
181
+ end
182
+
183
+ def pop_stash
184
+ git 'stash pop'
185
+ end
186
+
187
+ def rebase(from_branch, into_branch=nil)
188
+ ensure_branch_exists from_branch
189
+ ensure_branch_exists into_branch if into_branch
190
+ ensure_workdir_clean
191
+
192
+ git "checkout \"#{into_branch}\""
193
+ begin
194
+ merge = true
195
+ git "rebase \"#{from_branch}\""
196
+ rescue GitError => e
197
+ git 'rebase --abort' if e.conflict?
198
+ merge = false
199
+ raise e
200
+ end
201
+ end
202
+
203
+ private
204
+
205
+ # good way of making this more robust:
206
+ # https://github.com/CocoaPods/CocoaPods/blob/master/lib/cocoapods/executable.rb
207
+ # and:
208
+ # https://github.com/CocoaPods/CocoaPods/blob/master/lib/cocoapods/downloader/git.rb
209
+ def git(git_cmd)
210
+ output = nil
211
+ FileUtils.cd(@repo_root) { output = safe_exec("git #{git_cmd}") }
212
+ output
213
+ end
214
+
215
+ def safe_exec(cmd)
216
+ cmd_output = `#{cmd} 2>&1 3>&1`
217
+ raise GitError.new(cmd_output) unless $?.success?
218
+ cmd_output
219
+ end
220
+
221
+ def symbolicate(string)
222
+ string.gsub(/\s+/, "_").downcase.to_sym
223
+ end
224
+ end
225
+ end
@@ -0,0 +1 @@
1
+ require 'fwtoolkit/git_client/git_client'