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,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'