repo_manager 0.7.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 (116) hide show
  1. data/.gemfiles +115 -0
  2. data/.gitattributes +1 -0
  3. data/.gitignore +7 -0
  4. data/.rspec +3 -0
  5. data/.yardopts +11 -0
  6. data/Gemfile +11 -0
  7. data/Gemfile.lock +99 -0
  8. data/Guardfile +63 -0
  9. data/HISTORY.markdown +12 -0
  10. data/LICENSE +20 -0
  11. data/README.markdown +192 -0
  12. data/Rakefile +94 -0
  13. data/TODO.markdown +15 -0
  14. data/VERSION +1 -0
  15. data/bin/repo +151 -0
  16. data/cucumber.yml +28 -0
  17. data/examples/pc_saved_game_backup/.gitignore +2 -0
  18. data/examples/pc_saved_game_backup/INSTALL.markdown +420 -0
  19. data/examples/pc_saved_game_backup/README.markdown +108 -0
  20. data/examples/pc_saved_game_backup/remote/.gitignore +2 -0
  21. data/examples/pc_saved_game_backup/repo_manager/Gemfile +12 -0
  22. data/examples/pc_saved_game_backup/repo_manager/Gemfile.lock +66 -0
  23. data/examples/pc_saved_game_backup/repo_manager/assets/.gitignore +2 -0
  24. data/examples/pc_saved_game_backup/repo_manager/features/support/aruba.rb +15 -0
  25. data/examples/pc_saved_game_backup/repo_manager/features/support/env.rb +11 -0
  26. data/examples/pc_saved_game_backup/repo_manager/features/support/steps.rb +3 -0
  27. data/examples/pc_saved_game_backup/repo_manager/features/tasks/update.feature +144 -0
  28. data/examples/pc_saved_game_backup/repo_manager/global/default/asset.conf +2 -0
  29. data/examples/pc_saved_game_backup/repo_manager/repo.conf +64 -0
  30. data/examples/pc_saved_game_backup/repo_manager/tasks/.gitignore +0 -0
  31. data/examples/pc_saved_game_backup/repo_manager/tasks/remote.rb +57 -0
  32. data/examples/pc_saved_game_backup/repo_manager/tasks/update.rb +65 -0
  33. data/examples/pc_saved_game_backup/saved_games/hearts/save1 +1 -0
  34. data/examples/pc_saved_game_backup/saved_games/hearts/save2 +1 -0
  35. data/examples/pc_saved_game_backup/saved_games/mines/my_profile.ini +1 -0
  36. data/examples/pc_saved_game_backup/saved_games/mines/saves/save1 +1 -0
  37. data/examples/pc_saved_game_backup/saved_games/mines/saves/save2 +1 -0
  38. data/features/actions/git.feature +296 -0
  39. data/features/actions/help.feature +53 -0
  40. data/features/actions/list.feature +624 -0
  41. data/features/actions/path.feature +195 -0
  42. data/features/actions/status.feature +261 -0
  43. data/features/actions/task.feature +127 -0
  44. data/features/assets/configuration.feature +204 -0
  45. data/features/assets/rendering.feature +42 -0
  46. data/features/assets/user_attributes.feature +98 -0
  47. data/features/bin.feature +42 -0
  48. data/features/logger.feature +218 -0
  49. data/features/settings.feature +240 -0
  50. data/features/support/aruba.rb +15 -0
  51. data/features/support/env.rb +11 -0
  52. data/features/support/steps.rb +3 -0
  53. data/features/tasks/add/asset.feature +178 -0
  54. data/features/tasks/generate/init.feature +56 -0
  55. data/lib/repo_manager.rb +36 -0
  56. data/lib/repo_manager/actions.rb +8 -0
  57. data/lib/repo_manager/actions/action_helper.rb +39 -0
  58. data/lib/repo_manager/actions/app_action.rb +30 -0
  59. data/lib/repo_manager/actions/base_action.rb +296 -0
  60. data/lib/repo_manager/actions/git_action.rb +113 -0
  61. data/lib/repo_manager/actions/help_action.rb +52 -0
  62. data/lib/repo_manager/actions/list_action.rb +123 -0
  63. data/lib/repo_manager/actions/path_action.rb +22 -0
  64. data/lib/repo_manager/actions/status_action.rb +192 -0
  65. data/lib/repo_manager/actions/task_action.rb +71 -0
  66. data/lib/repo_manager/app.rb +116 -0
  67. data/lib/repo_manager/assets.rb +3 -0
  68. data/lib/repo_manager/assets/app_asset.rb +15 -0
  69. data/lib/repo_manager/assets/asset_accessors.rb +67 -0
  70. data/lib/repo_manager/assets/asset_configuration.rb +137 -0
  71. data/lib/repo_manager/assets/asset_manager.rb +72 -0
  72. data/lib/repo_manager/assets/base_asset.rb +199 -0
  73. data/lib/repo_manager/assets/repo_asset.rb +30 -0
  74. data/lib/repo_manager/core.rb +2 -0
  75. data/lib/repo_manager/core/array.rb +21 -0
  76. data/lib/repo_manager/core/hash.rb +83 -0
  77. data/lib/repo_manager/errors.rb +10 -0
  78. data/lib/repo_manager/extensions/hash.rb +86 -0
  79. data/lib/repo_manager/git.rb +2 -0
  80. data/lib/repo_manager/git/lib.rb +69 -0
  81. data/lib/repo_manager/git/status.rb +196 -0
  82. data/lib/repo_manager/logger.rb +39 -0
  83. data/lib/repo_manager/settings.rb +98 -0
  84. data/lib/repo_manager/tasks.rb +3 -0
  85. data/lib/repo_manager/tasks/add/asset.rb +213 -0
  86. data/lib/repo_manager/tasks/generate/init.rb +42 -0
  87. data/lib/repo_manager/tasks/generate/templates/config/repo.conf.tt +61 -0
  88. data/lib/repo_manager/tasks/generate/templates/init/assets/.gitignore +0 -0
  89. data/lib/repo_manager/tasks/generate/templates/init/global/default/asset.conf +2 -0
  90. data/lib/repo_manager/tasks/generate/templates/init/tasks/.gitignore +0 -0
  91. data/lib/repo_manager/tasks/task_manager.rb +166 -0
  92. data/lib/repo_manager/tasks/thor_helper.rb +29 -0
  93. data/lib/repo_manager/test/asset_steps.rb +19 -0
  94. data/lib/repo_manager/test/base_steps.rb +152 -0
  95. data/lib/repo_manager/test/repo_api.rb +41 -0
  96. data/lib/repo_manager/test/repo_steps.rb +83 -0
  97. data/lib/repo_manager/test/test_api.rb +88 -0
  98. data/lib/repo_manager/views.rb +2 -0
  99. data/lib/repo_manager/views/app_view.rb +15 -0
  100. data/lib/repo_manager/views/base_view.rb +137 -0
  101. data/lib/repo_manager/views/templates/css/basic.css +26 -0
  102. data/lib/repo_manager/views/templates/default.erb +40 -0
  103. data/lib/repo_manager/views/templates/default.slim +37 -0
  104. data/lib/repo_manager/views/view_helper.rb +55 -0
  105. data/repo_manager.gemspec +75 -0
  106. data/spec/basic_app/actions/action_helper_spec.rb +54 -0
  107. data/spec/basic_app/assets/base_asset_spec.rb +210 -0
  108. data/spec/basic_app/core_spec.rb +78 -0
  109. data/spec/basic_app/settings_spec.rb +64 -0
  110. data/spec/basic_app/views/view_helper_spec.rb +28 -0
  111. data/spec/basic_gem/aruba_helper_spec.rb +33 -0
  112. data/spec/basic_gem/basic_gem_spec.rb +84 -0
  113. data/spec/basic_gem/gemspec_spec.rb +68 -0
  114. data/spec/repo_manager/git_spec.rb +31 -0
  115. data/spec/spec_helper.rb +25 -0
  116. metadata +472 -0
data/Rakefile ADDED
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+
3
+ # Bundler is managing $LOAD_PATH, any gem needed by this Rakefile must be
4
+ # listed as a development dependency in the gemspec
5
+ require 'bundler/setup'
6
+ require 'bundler/gem_tasks'
7
+
8
+ require 'rbconfig'
9
+ WINDOWS = RbConfig::CONFIG['host_os'] =~ /msdos|mswin|win32|mingw/i unless defined?(WINDOWS)
10
+
11
+ require 'rspec/core/rake_task'
12
+ desc "Run RSpec"
13
+ RSpec::Core::RakeTask.new do |spec|
14
+ spec.pattern = 'spec/**/*_spec.rb'
15
+ end
16
+
17
+ require 'cucumber/rake/task'
18
+ Cucumber::Rake::Task.new do |t|
19
+
20
+ opts = []
21
+ opts << ["--color"]
22
+ opts << ["--format pretty"]
23
+ opts << ["--strict"]
24
+ opts << ["-r features"]
25
+ opts << ["--no-profile"]
26
+ opts << ["--tags ~@wip"]
27
+ opts << ["--tags ~@windows"] unless WINDOWS
28
+ opts << ["--tags ~@posix"] if WINDOWS
29
+
30
+ t.cucumber_opts = opts
31
+ end
32
+
33
+ desc "Run specs, both RSpec and Cucumber"
34
+ task :test => [:spec, :cucumber]
35
+
36
+ task :default => :test
37
+
38
+ namespace :doc do
39
+
40
+ doc_version = File.open(File.join(File.dirname(__FILE__), 'VERSION'), "r") { |f| f.read }
41
+ project_root = File.expand_path(File.dirname(__FILE__))
42
+ doc_destination = File.join(project_root, 'rdoc')
43
+
44
+ require 'yard'
45
+
46
+ YARD::Rake::YardocTask.new(:generate) do |yt|
47
+ yt.options = ['--output-dir', doc_destination,
48
+ '--title', "RepoManager #{doc_version} Documentation",
49
+ '--main', "README.markdown"
50
+ ]
51
+ end
52
+
53
+ desc "Remove generated documenation"
54
+ task :clean do
55
+ rm_r doc_destination if File.exists?(doc_destination)
56
+ end
57
+
58
+ desc "List undocumented objects"
59
+ task :undocumented do
60
+ system('yard stats --list-undoc')
61
+ end
62
+
63
+ end
64
+
65
+ # put the gemfiles task in the bundler dependency chain
66
+ task :build => [:gemfiles]
67
+ task :install => [:gemfiles]
68
+ task :release => [:gemfiles]
69
+
70
+ desc "Generate .gemfiles via 'git ls-files'"
71
+ task :gemfiles do
72
+ files = `git ls-files`
73
+
74
+ filename = File.join(File.dirname(__FILE__), '.gemfiles')
75
+ cached_files = nil
76
+ if File.exists?(filename)
77
+ puts ".gemfiles exists, reading..."
78
+ cached_files = File.open(filename, "rb") {|f| f.read}
79
+ end
80
+
81
+ if cached_files && cached_files.match("\r\n")
82
+ puts ".gemfiles using DOS EOL"
83
+ files.gsub!(/\n/, "\r\n")
84
+ end
85
+
86
+ if cached_files != files
87
+ puts ".gemfiles updating"
88
+ File.open(filename, 'wb') {|f| f.write(files)}
89
+ else
90
+ puts ".gemfiles update not required"
91
+ end
92
+
93
+ raise "unable to process .gemfiles" unless files
94
+ end
data/TODO.markdown ADDED
@@ -0,0 +1,15 @@
1
+ TODO
2
+ ====
3
+
4
+ * remove git gem and duplicate needed method. The use of ENV[] will break on
5
+ win32 and ruby 1.9.3
6
+ * add find action that finds a repo based on all strings in the repo config
7
+ * provide native repo completion via --completion option so the entire ARGV can
8
+ be scanned and passed back to bash. We have to load ruby anyway, might as
9
+ well provide completion for commands and options too.
10
+ * status should show summary at the end
11
+ * add feature tests for all combinations of XY result codes from 'git status --porcelain'
12
+ * status command should have option to show last commit information
13
+ * native git commands need to preserve ANSI escape codes for coloring
14
+ * add man page via markdown and ronn. Change 'help' action to call man
15
+ page if man available.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7.1
data/bin/repo ADDED
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'repo_manager'
4
+ require 'optparse'
5
+ require 'term/ansicolor'
6
+ require 'fileutils'
7
+
8
+ available_actions = RepoManager::AVAILABLE_ACTIONS
9
+
10
+ banner = <<BANNER
11
+ repo: CLI for batch management of multiple Git repositories
12
+
13
+ Usage: repo [options] action [filters|action pass-through options] [options]
14
+ BANNER
15
+ banner << "\nActions: #{available_actions.join(' ')}\n" unless available_actions.empty?
16
+
17
+ help = banner
18
+ help += <<HELP
19
+
20
+ Use 'repo help' for help on actions.
21
+
22
+ repo help task
23
+ repo help git
24
+
25
+ Examples:
26
+
27
+ repo list my_repo1 my_repo2
28
+ repo list --filter=my_repo1,my_repo2
29
+
30
+ repo list --filter=my.*
31
+ repo list my.*
32
+
33
+ repo --verbose --no-color config --list --filter=my_repo1,my_repo2
34
+ repo --verbose --no-color config core.autocrlf true filter=my.*
35
+ repo --verbose --no-color git config --list
36
+ repo --verbose --no-color config --list
37
+
38
+ Most Git commands can be passed directly, these are equivalent
39
+
40
+ repo add .
41
+ repo git add .
42
+
43
+ General options:
44
+ (use 'repo help action' for action options)
45
+
46
+ HELP
47
+
48
+ # get options from the command line, these options override both config files
49
+ # and defaults
50
+ options = {}
51
+ optparser = OptionParser.new do |opts|
52
+ opts.banner = help
53
+
54
+ opts.on("-T", "--tasks", "List tasks") do |t|
55
+ options[:tasks] = t
56
+ end
57
+
58
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
59
+ options[:verbose] = v
60
+ end
61
+
62
+ opts.on("-c", "--[no-]coloring [MODE]", "--[no-]color [MODE]", "ANSI color in output. MODE=AUTO (default) or ALWAYS") do |c|
63
+ options[:color] = c.nil? ? "AUTO" : c
64
+ options[:color].upcase! if options[:color]
65
+ unless [nil, false, "AUTO", "ALWAYS"].include?(options[:color])
66
+ puts "repo, invalid color option: #{options[:color]}"
67
+ exit 1
68
+ end
69
+ end
70
+
71
+ opts.on("--[no-]config FILE", "Load configuration options from FILE") do |file|
72
+ options[:config] = file
73
+ end
74
+
75
+ opts.on("--version", "Display current version and exit") do
76
+ puts "repo_manager, version " + RepoManager.version
77
+ exit 0
78
+ end
79
+
80
+ # no argument, shows at tail. This will print an options summary.
81
+ opts.on_tail("-h", "--help", "Show this message") do
82
+ puts opts
83
+ exit 0
84
+ end
85
+
86
+ end
87
+
88
+ # first pass, process until the action/subcommand, errors will be raised for
89
+ # invalid options that occur before the action/subcommand
90
+ begin
91
+ optparser.order!
92
+ rescue OptionParser::InvalidOption => e
93
+ puts "repo #{e}"
94
+ puts "repo --help for more information"
95
+ exit 1
96
+ end
97
+
98
+
99
+ # OptionParser is too helpful and matches short options with long. Before the
100
+ # second pass, replace short git options with long because we can't tell
101
+ # OptionParser to stop matching short options to long.
102
+ ARGV.each_with_index do |arg, index|
103
+ # check and replace each short git option
104
+ # that could be parsed by main parser
105
+ case arg
106
+ when '-m'
107
+ ARGV[index] = '--message'
108
+ end
109
+ end
110
+
111
+ # second pass find all global options that may come after the action/subcommand
112
+ # and its args, no errors raised, validity will be checked by action parser
113
+ argv = []
114
+ while unknown_arg = ARGV.shift
115
+ argv << unknown_arg
116
+ begin
117
+ optparser.order!
118
+ rescue OptionParser::InvalidOption => e
119
+ # put unknown args back on ARGV
120
+ e.recover(ARGV)
121
+ end
122
+ end
123
+
124
+ # settings from config file, if it exists, will not overwrite command line options
125
+ settings = RepoManager::Settings.new(FileUtils.pwd, options)
126
+ color = settings.options[:color]
127
+
128
+ # add summary of general options for use by action help commands
129
+ configuration = settings.to_hash
130
+
131
+ if STDOUT.isatty || (color == 'ALWAYS')
132
+ Term::ANSIColor::coloring = color
133
+
134
+ if color && RepoManager::WINDOWS
135
+ unless ENV['ANSICON']
136
+ begin
137
+ require 'Win32/Console/ANSI'
138
+ rescue LoadError
139
+ Term::ANSIColor::coloring = false
140
+ STDERR.puts 'WARNING: You must "gem install win32console" (1.2.0 or higher) or use the ANSICON driver (https://github.com/adoxa/ansicon) to get color output on MRI/Windows'
141
+ end
142
+ end
143
+ end
144
+
145
+ else
146
+ Term::ANSIColor::coloring = false
147
+ end
148
+
149
+ app = RepoManager::App.new(argv, configuration)
150
+ app.option_parser = optparser
151
+ app.execute
data/cucumber.yml ADDED
@@ -0,0 +1,28 @@
1
+ <%
2
+ require 'rbconfig'
3
+ WINDOWS = RbConfig::CONFIG['host_os'] =~ /msdos|mswin|win32|mingw/i unless defined?(WINDOWS)
4
+
5
+ opts = []
6
+ opts << ["--color"]
7
+ opts << ["--format pretty"]
8
+ opts << ["--strict"]
9
+ opts << ["-r features"]
10
+ opts << ["--no-profile"]
11
+ opts << ["--tags ~@wip"]
12
+ opts << ["--tags ~@windows"] unless WINDOWS
13
+ opts << ["--tags ~@posix"] if WINDOWS
14
+
15
+ std_opts = opts.join(' ')
16
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
17
+ rerun_opts = rerun.to_s.strip.empty? ? "--format pretty" : "--format pretty #{rerun}"
18
+
19
+ %>
20
+ # define cucumber profiles
21
+ #
22
+ # Example usage:
23
+ #
24
+ # bundle exec cucumber --profile wip
25
+ ---
26
+ default: <%= std_opts %> -r features
27
+ wip: --tags @wip:3 --wip -r features
28
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip -r features
@@ -0,0 +1,2 @@
1
+ /repo.log
2
+ /repo_manager/tmp
@@ -0,0 +1,420 @@
1
+ Creating the RepoManager Saved Game Backup Configuration
2
+ ====================================================
3
+
4
+ > NOTE for Windows users
5
+ >
6
+ > The given instruction are intended for a Bash shell. Bash is not
7
+ > required to use RepoManager, but it does make using the command prompt much
8
+ > more flexible and productive. The MSYS distribution of portable Git
9
+ > includes a lean and stable Bash environment.
10
+
11
+ Initial configuration
12
+ ---------------------
13
+
14
+ ### install repo_manager
15
+
16
+ gem install repo_manager
17
+
18
+ ### create configuration
19
+
20
+ The following commands were used to create this example folder from
21
+ scratch.
22
+
23
+ mkdir -p examples/pc_saved_game_backup && cd examples/pc_saved_game_backup
24
+
25
+ Create configuration structure with the built-in 'generate:init' task
26
+
27
+ > NOTE
28
+ >
29
+ > We are creating a local configuration. For a global configuration, you would
30
+ > execute the init command in your home folder
31
+
32
+ repo generate:init repo_manager
33
+
34
+ We are going to keep this under version control
35
+
36
+ git init
37
+ git add .
38
+ git commit -m "initial commit"
39
+ echo "/repo.log" > .gitignore
40
+ echo "/repo_manager/tmp" >> .gitignore
41
+
42
+ Change the generated paths from absolute to relative to make this example
43
+ portable.
44
+
45
+ diff --git a/repo_manager/repo.conf b/repo_manager/repo.conf
46
+ index ce4418d..3cc6dbe 100644
47
+ --- a/repo_manager/repo.conf
48
+ +++ b/repo_manager/repo.conf
49
+ @@ -11,7 +11,7 @@ options:
50
+ folders:
51
+
52
+ # main repo configuration files
53
+ - assets : /home/robert/examples/pc_saved_game_backup/repo_manager/assets
54
+ + assets : assets
55
+
56
+ #
57
+ # repo user tasks, file extentions can be '.rb' or '.thor'
58
+ @@ -26,7 +26,7 @@ folders:
59
+ #
60
+ # c:/dat/condenser/tasks
61
+ #
62
+ - tasks : /home/robert/examples/pc_saved_game_backup/repo_manager/tasks
63
+ + tasks : tasks
64
+
65
+ # git commands must be whitelisted
66
+ commands:
67
+ @@ -55,7 +55,7 @@ logging:
68
+ name : logfile
69
+ level : info
70
+ truncate : true
71
+ - filename : '/home/robert/examples/pc_saved_game_backup/repo_manager/repo.log'
72
+ + filename : 'repo.log'
73
+ layout:
74
+ type : Pattern
75
+ pattern : '[%d] %l %c : %m\n'
76
+
77
+ ### add sample data
78
+
79
+ Add a few example save game folder. These folders would normally be
80
+ scattered over the file system.
81
+
82
+ mines
83
+
84
+ mkdir -p saved_games/mines/saves
85
+
86
+ # profile data will not be stored in the Git repo since it may differ from PC to PC
87
+ echo "# dummy profile data" > mines/my_profile.ini
88
+
89
+ echo "# dummy save" > saved_games/mines/saves/save1
90
+ echo "# dummy save" > saved_games/mines/saves/save2
91
+
92
+ hearts
93
+
94
+ mkdir -p saved_games/hearts
95
+
96
+ echo "# dummy save" > saved_games/hearts/save1
97
+ echo "# dummy save" > saved_games/hearts/save2
98
+
99
+ ### create remote folder
100
+
101
+ This folder will act as a remote to hold bare Git repositories. These
102
+ repos will store backups of our game saves, normally, this folder would be
103
+ on a remote server, NAS, or Drop Box like service.
104
+
105
+ mkdir remote
106
+
107
+ remote/.gitignore
108
+
109
+ *
110
+ !/.gitignore
111
+
112
+
113
+ Create the specialized 'git init' task
114
+ --------------------------------------
115
+
116
+ User tasks can be added directly to the repo_manager/tasks folder. This one
117
+ is 'repo_manager/tasks/remote.rb'. It doesn't use any RepoManager specific features,
118
+ instead, it calls git directly via Thor's 'run' command. Adding the script
119
+ this way will keep this related functionality with this specific RepoManager
120
+ configuration. Run 'repo -T' to see a full list of built-in tasks as well
121
+ as user defined tasks.
122
+
123
+ repo_manager/tasks/remote.rb
124
+
125
+ require 'fileutils'
126
+
127
+ module RepoManager
128
+
129
+ class Generate < Thor
130
+
131
+ # full path to the remote folder
132
+ REMOTE = File.expand_path('remote')
133
+
134
+ # Create, add, and commit the contents of the current working directory and
135
+ # then push it to a predefined remote folder
136
+ #
137
+ # @example From the repo working
138
+ #
139
+ # cd ~/my_repo_name
140
+ # repo generate:remote my_repo_name
141
+ #
142
+ # @example Specify the path to the working folder
143
+ #
144
+ # repo generate:remote my_repo_name --path=/path/to/my_repo_name
145
+
146
+ method_option :remote, :type => :string, :desc => "remote folder or git host, defaults to '#{REMOTE}'"
147
+ method_option :path, :type => :string, :desc => "path to working folder, defaults to CWD"
148
+
149
+ desc "remote REPO_NAME", "init a git repo in CWD and push to remote '#{REMOTE}'"
150
+ def remote(name)
151
+ path = options[:path] || FileUtils.pwd
152
+ remote = options[:remote] || "#{File.join(REMOTE, name + '.git')}"
153
+
154
+ Dir.chdir path do
155
+ run("git init")
156
+
157
+ # core config with windows in mind but works fine on POSIX
158
+ run("git config core.autocrlf false")
159
+ run("git config core.filemode false")
160
+ exit $?.exitstatus if ($?.exitstatus > 1)
161
+
162
+ # add everthing and commit
163
+ run("git add .")
164
+ run("git commit --message #{shell_quote('initial commit')}")
165
+ exit $?.exitstatus if ($?.exitstatus > 1)
166
+
167
+ # remove old origin first, if it exists
168
+ run("git remote add origin #{remote}")
169
+ run("git config branch.master.remote origin")
170
+ run("git config branch.master.merge refs/heads/master")
171
+ exit $?.exitstatus if ($?.exitstatus > 1)
172
+ end
173
+
174
+ run("git clone --bare #{shell_quote(path)} #{remote}")
175
+ exit $?.exitstatus if ($?.exitstatus > 1)
176
+
177
+ say "init done on '#{name}'", :green
178
+ end
179
+
180
+ end
181
+ end
182
+
183
+ ### add remotes
184
+
185
+ In one step, we will initialize a new git repository with the working folder's
186
+ content and push to a new bare repository for backup.
187
+
188
+ > Normally, you don't need to specify the --path if you are already in the
189
+ > working folder and the repo_manager can find its global config file. For this
190
+ > example, we are using relative paths and will specify the working folder
191
+ > on the command line via the '--path' option.
192
+
193
+ repo generate:remote mines --path=saved_games/mines/saves
194
+ repo generate:remote hearts --path=saved_games/hearts
195
+
196
+ ### create the repo_manager asset configuration files
197
+
198
+ repo add:asset saved_games/mines/saves --name=mines --force
199
+ repo add:asset saved_games/hearts --force
200
+
201
+
202
+ Create the specialized Update task
203
+ ----------------------------------
204
+
205
+ repo_manager/tasks/update.rb
206
+
207
+ module RepoManager
208
+ class Action < Thor
209
+ namespace :action
210
+ include Thor::Actions
211
+ include RepoManager::ThorHelper
212
+
213
+ class_option :force, :type => :boolean, :desc => "Force overwrite and answer 'yes' to any prompts"
214
+
215
+ method_option :repos, :type => :string, :desc => "Restrict update to comma delimited list of repo names", :banner => "repo1,repo2"
216
+ method_option :message, :type => :string, :desc => "Override 'automatic commit' message"
217
+ method_option 'no-push', :type => :boolean, :default => false, :desc => "Force overwrite of existing config file"
218
+
219
+ desc "update", "run repo add -A, repo commit, and repo push on all modified repos"
220
+ def update
221
+
222
+ initial_filter = options[:repos] ? "--repos=#{options[:repos]}" : ""
223
+ output = run("repo status --short --unmodified=HIDE --no-verbose --no-color #{initial_filter}", :capture => true)
224
+
225
+ case $?.exitstatus
226
+ when 0
227
+ say 'no changed repos', :green
228
+ else
229
+
230
+ unless output
231
+ say "failed to successfully run 'repo status'", :red
232
+ exit $?.exitstatus
233
+ end
234
+
235
+ repos = []
236
+ output = output.split("\n")
237
+ while line = output.shift
238
+ st,repo = line.split("\t")
239
+ repos << repo
240
+ end
241
+ filter = repos.join(',')
242
+
243
+ unless options[:force]
244
+ say "Repo(s) '#{filter}' have changed."
245
+ unless ask("Add, commit and push them? (y/n)") == 'y'
246
+ say "aborting"
247
+ exit 0
248
+ end
249
+ end
250
+
251
+ say "updating #{filter}"
252
+
253
+ run "repo add -A --no-verbose --repos #{filter}"
254
+ exit $?.exitstatus if ($?.exitstatus > 1)
255
+
256
+ commit_message = options[:message] || "automatic commit @ #{Time.now}"
257
+ run "repo commit --message=#{shell_quote(commit_message)} --no-verbose --repos #{filter}"
258
+ exit $?.exitstatus if ($?.exitstatus > 1)
259
+
260
+ unless options['no-push']
261
+ run "repo push --no-verbose --repos #{filter}"
262
+ exit $?.exitstatus if ($?.exitstatus > 1)
263
+ end
264
+
265
+ say "update finished", :green
266
+ end
267
+
268
+ end
269
+ end
270
+ end
271
+
272
+ ### whitelist non-default Git commands
273
+
274
+ Only a small subset of non-destructive git commands are enabled by default. We will
275
+ add the commands needed by our user task to the commands whitelist.
276
+
277
+ Add 'push, add, and commit' to the commands whitelist
278
+
279
+ diff --git a/repo_manager/repo.conf b/repo_manager/repo.conf
280
+ index 3cc6dbe..226b8c0 100644
281
+ --- a/repo_manager/repo.conf
282
+ +++ b/repo_manager/repo.conf
283
+ @@ -36,6 +36,9 @@ commands:
284
+ - ls-files
285
+ - show
286
+ - status
287
+ +- push
288
+ +- add
289
+ +- commit
290
+
291
+ Testing user tasks with Cucumber
292
+ --------------------------------------
293
+
294
+ ### Add a Gemfile for use by Bundler
295
+
296
+ repo_manager/Gemfile
297
+
298
+ source "http://rubygems.org"
299
+
300
+ gem "repo_manager"
301
+
302
+ gem "bundler", ">= 1.0.14"
303
+ gem "rspec", ">= 2.6.0"
304
+ gem "cucumber", "~> 1.0"
305
+ gem "aruba", "= 0.4.5"
306
+
307
+ gem "win32console", :platforms => [:mingw, :mswin]
308
+
309
+ ### Install the dependencies
310
+
311
+ gem install bundler
312
+
313
+ cd repo_manager
314
+ bundle
315
+
316
+ ### Add Cucumber features and support files
317
+
318
+ repo_manager/features/tasks/update.feature
319
+
320
+ > NOTE: This is an excerpt, see the file for the full listing of functional tests
321
+
322
+ @announce
323
+ Feature: Automatically commit and update multiple repos
324
+
325
+ Background: Test repositories and a valid config file
326
+ Given a repo in folder "test_path_1" with the following:
327
+ | filename | status | content |
328
+ | .gitignore | C | |
329
+ And a repo in folder "test_path_2" with the following:
330
+ | filename | status | content |
331
+ | .gitignore | C | |
332
+ And a file named "repo.conf" with:
333
+ """
334
+ ---
335
+ folders:
336
+ assets : repo/asset/configuration/files
337
+ """
338
+ And the folder "repo/asset/configuration/files" with the following asset configurations:
339
+ | name | path |
340
+ | test1 | test_path_1 |
341
+ | test2 | test_path_2 |
342
+
343
+
344
+ Scenario: No uncommitted changes
345
+ When I run `repo action:update`
346
+ Then the output should contain:
347
+ """
348
+ no changed repos
349
+ """
350
+
351
+ ...
352
+
353
+ repo_manager/features/support/steps.rb
354
+
355
+ require 'repo_manager/test/base_steps'
356
+ require 'repo_manager/test/asset_steps'
357
+ require 'repo_manager/test/repo_steps'
358
+
359
+ repo_manager/features/support/env.rb
360
+
361
+ require 'repo_manager'
362
+ require 'aruba/cucumber'
363
+ require 'rspec/expectations'
364
+
365
+ repo_manager/features/support/aruba.rb
366
+
367
+ require 'aruba/api'
368
+ require 'fileutils'
369
+
370
+ module Aruba
371
+ module Api
372
+
373
+ # override aruba avoid 'current_ruby' call and make sure
374
+ # that binary run on Win32 without the binstubs
375
+ def detect_ruby(cmd)
376
+ wrapper = which('repo')
377
+ cmd = cmd.gsub(/^repo/, "ruby -S #{wrapper}") if wrapper
378
+ cmd
379
+ end
380
+ end
381
+ end
382
+
383
+ ### Run tests
384
+
385
+ bundle exec cucumber
386
+
387
+ Bash completion
388
+ ---------------
389
+
390
+ Handy functions for use under Bash. These work fine on Win32 using
391
+ Git-Bash.
392
+
393
+ ### CD command for working folders
394
+
395
+ rpushd: repo pushd (push directory). Wrapper for 'pushd'.
396
+
397
+ ### Completion for repo names
398
+
399
+ rcd: repo cd (change directory). Wrapper for 'cd', allows for simple cd <repo
400
+ name> to the working folder on the filesystem referenced by the 'path'
401
+ configuration variable.
402
+
403
+ Source these functions in your .bashrc
404
+
405
+ function rcd(){ cd "$(repo --match=ONE --no-color path $@)"; }
406
+ function rpushd(){ pushd "$(repo path --match=ONE --no-color $@)"; }
407
+ alias rpopd="popd"
408
+
409
+ # provide completion for repo names
410
+ function _repo_names()
411
+ {
412
+ local cur opts prev
413
+ COMPREPLY=()
414
+ cur="${COMP_WORDS[COMP_CWORD]}"
415
+ opts=`repo list --list=name --no-color`
416
+
417
+ COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
418
+ return 0
419
+ }
420
+ complete -F _repo_names rcd rpushd repo