repo_manager 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemfiles +115 -0
- data/.gitattributes +1 -0
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.yardopts +11 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +99 -0
- data/Guardfile +63 -0
- data/HISTORY.markdown +12 -0
- data/LICENSE +20 -0
- data/README.markdown +192 -0
- data/Rakefile +94 -0
- data/TODO.markdown +15 -0
- data/VERSION +1 -0
- data/bin/repo +151 -0
- data/cucumber.yml +28 -0
- data/examples/pc_saved_game_backup/.gitignore +2 -0
- data/examples/pc_saved_game_backup/INSTALL.markdown +420 -0
- data/examples/pc_saved_game_backup/README.markdown +108 -0
- data/examples/pc_saved_game_backup/remote/.gitignore +2 -0
- data/examples/pc_saved_game_backup/repo_manager/Gemfile +12 -0
- data/examples/pc_saved_game_backup/repo_manager/Gemfile.lock +66 -0
- data/examples/pc_saved_game_backup/repo_manager/assets/.gitignore +2 -0
- data/examples/pc_saved_game_backup/repo_manager/features/support/aruba.rb +15 -0
- data/examples/pc_saved_game_backup/repo_manager/features/support/env.rb +11 -0
- data/examples/pc_saved_game_backup/repo_manager/features/support/steps.rb +3 -0
- data/examples/pc_saved_game_backup/repo_manager/features/tasks/update.feature +144 -0
- data/examples/pc_saved_game_backup/repo_manager/global/default/asset.conf +2 -0
- data/examples/pc_saved_game_backup/repo_manager/repo.conf +64 -0
- data/examples/pc_saved_game_backup/repo_manager/tasks/.gitignore +0 -0
- data/examples/pc_saved_game_backup/repo_manager/tasks/remote.rb +57 -0
- data/examples/pc_saved_game_backup/repo_manager/tasks/update.rb +65 -0
- data/examples/pc_saved_game_backup/saved_games/hearts/save1 +1 -0
- data/examples/pc_saved_game_backup/saved_games/hearts/save2 +1 -0
- data/examples/pc_saved_game_backup/saved_games/mines/my_profile.ini +1 -0
- data/examples/pc_saved_game_backup/saved_games/mines/saves/save1 +1 -0
- data/examples/pc_saved_game_backup/saved_games/mines/saves/save2 +1 -0
- data/features/actions/git.feature +296 -0
- data/features/actions/help.feature +53 -0
- data/features/actions/list.feature +624 -0
- data/features/actions/path.feature +195 -0
- data/features/actions/status.feature +261 -0
- data/features/actions/task.feature +127 -0
- data/features/assets/configuration.feature +204 -0
- data/features/assets/rendering.feature +42 -0
- data/features/assets/user_attributes.feature +98 -0
- data/features/bin.feature +42 -0
- data/features/logger.feature +218 -0
- data/features/settings.feature +240 -0
- data/features/support/aruba.rb +15 -0
- data/features/support/env.rb +11 -0
- data/features/support/steps.rb +3 -0
- data/features/tasks/add/asset.feature +178 -0
- data/features/tasks/generate/init.feature +56 -0
- data/lib/repo_manager.rb +36 -0
- data/lib/repo_manager/actions.rb +8 -0
- data/lib/repo_manager/actions/action_helper.rb +39 -0
- data/lib/repo_manager/actions/app_action.rb +30 -0
- data/lib/repo_manager/actions/base_action.rb +296 -0
- data/lib/repo_manager/actions/git_action.rb +113 -0
- data/lib/repo_manager/actions/help_action.rb +52 -0
- data/lib/repo_manager/actions/list_action.rb +123 -0
- data/lib/repo_manager/actions/path_action.rb +22 -0
- data/lib/repo_manager/actions/status_action.rb +192 -0
- data/lib/repo_manager/actions/task_action.rb +71 -0
- data/lib/repo_manager/app.rb +116 -0
- data/lib/repo_manager/assets.rb +3 -0
- data/lib/repo_manager/assets/app_asset.rb +15 -0
- data/lib/repo_manager/assets/asset_accessors.rb +67 -0
- data/lib/repo_manager/assets/asset_configuration.rb +137 -0
- data/lib/repo_manager/assets/asset_manager.rb +72 -0
- data/lib/repo_manager/assets/base_asset.rb +199 -0
- data/lib/repo_manager/assets/repo_asset.rb +30 -0
- data/lib/repo_manager/core.rb +2 -0
- data/lib/repo_manager/core/array.rb +21 -0
- data/lib/repo_manager/core/hash.rb +83 -0
- data/lib/repo_manager/errors.rb +10 -0
- data/lib/repo_manager/extensions/hash.rb +86 -0
- data/lib/repo_manager/git.rb +2 -0
- data/lib/repo_manager/git/lib.rb +69 -0
- data/lib/repo_manager/git/status.rb +196 -0
- data/lib/repo_manager/logger.rb +39 -0
- data/lib/repo_manager/settings.rb +98 -0
- data/lib/repo_manager/tasks.rb +3 -0
- data/lib/repo_manager/tasks/add/asset.rb +213 -0
- data/lib/repo_manager/tasks/generate/init.rb +42 -0
- data/lib/repo_manager/tasks/generate/templates/config/repo.conf.tt +61 -0
- data/lib/repo_manager/tasks/generate/templates/init/assets/.gitignore +0 -0
- data/lib/repo_manager/tasks/generate/templates/init/global/default/asset.conf +2 -0
- data/lib/repo_manager/tasks/generate/templates/init/tasks/.gitignore +0 -0
- data/lib/repo_manager/tasks/task_manager.rb +166 -0
- data/lib/repo_manager/tasks/thor_helper.rb +29 -0
- data/lib/repo_manager/test/asset_steps.rb +19 -0
- data/lib/repo_manager/test/base_steps.rb +152 -0
- data/lib/repo_manager/test/repo_api.rb +41 -0
- data/lib/repo_manager/test/repo_steps.rb +83 -0
- data/lib/repo_manager/test/test_api.rb +88 -0
- data/lib/repo_manager/views.rb +2 -0
- data/lib/repo_manager/views/app_view.rb +15 -0
- data/lib/repo_manager/views/base_view.rb +137 -0
- data/lib/repo_manager/views/templates/css/basic.css +26 -0
- data/lib/repo_manager/views/templates/default.erb +40 -0
- data/lib/repo_manager/views/templates/default.slim +37 -0
- data/lib/repo_manager/views/view_helper.rb +55 -0
- data/repo_manager.gemspec +75 -0
- data/spec/basic_app/actions/action_helper_spec.rb +54 -0
- data/spec/basic_app/assets/base_asset_spec.rb +210 -0
- data/spec/basic_app/core_spec.rb +78 -0
- data/spec/basic_app/settings_spec.rb +64 -0
- data/spec/basic_app/views/view_helper_spec.rb +28 -0
- data/spec/basic_gem/aruba_helper_spec.rb +33 -0
- data/spec/basic_gem/basic_gem_spec.rb +84 -0
- data/spec/basic_gem/gemspec_spec.rb +68 -0
- data/spec/repo_manager/git_spec.rb +31 -0
- data/spec/spec_helper.rb +25 -0
- 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,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
|