garlic 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/History.txt +64 -0
- data/License.txt +20 -0
- data/README.rdoc +143 -0
- data/Rakefile +57 -0
- data/Todo.txt +4 -0
- data/VERSION +1 -0
- data/bin/garlic +80 -0
- data/garlic.gemspec +66 -0
- data/lib/garlic.rb +34 -0
- data/lib/garlic/configurator.rb +59 -0
- data/lib/garlic/generator.rb +29 -0
- data/lib/garlic/repo.rb +121 -0
- data/lib/garlic/session.rb +145 -0
- data/lib/garlic/shell.rb +67 -0
- data/lib/garlic/target.rb +126 -0
- data/lib/garlic/tasks.rb +23 -0
- data/lib/tabtab_definitions/garlic.rb +15 -0
- data/sh/garlic.sh +34 -0
- data/spec/garlic/repo_spec.rb +38 -0
- data/spec/spec_helper.rb +2 -0
- data/templates/default.rb +26 -0
- data/templates/rspec.rb +32 -0
- data/templates/shoulda.rb +28 -0
- metadata +79 -0
data/.gitignore
ADDED
data/History.txt
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
== 0.1.10
|
2
|
+
|
3
|
+
* 2 minor enhancements
|
4
|
+
* updated gemspec for gemcutter and rubyforge
|
5
|
+
* templates now include rails 2.3
|
6
|
+
|
7
|
+
|
8
|
+
== 0.1.9
|
9
|
+
|
10
|
+
* 1 major enhancement
|
11
|
+
* added garlic shell commands (sh/garlic.sh) for easing the garlic workflow
|
12
|
+
to use them, add this to your ~/.profile
|
13
|
+
|
14
|
+
source `garlic --path`/sh/garlic.sh
|
15
|
+
|
16
|
+
== 0.1.8
|
17
|
+
|
18
|
+
* 1 bugfix
|
19
|
+
* fix problem where dependencies weren't checking out repo tags or branches properly
|
20
|
+
|
21
|
+
== 0.1.7
|
22
|
+
|
23
|
+
* 2 minor enhancement
|
24
|
+
* Fix problem whereby garlic update_repos wasn't updating repos correctly
|
25
|
+
* utilise Garlic::Generator in tabtab definition
|
26
|
+
|
27
|
+
== 0.1.6 2008-11-27
|
28
|
+
|
29
|
+
* 3 minor enhancements
|
30
|
+
* Updated Readme/TODO
|
31
|
+
* Some crufty output is now suppressed/removed
|
32
|
+
* garlic all command cleans the work path
|
33
|
+
|
34
|
+
* 1 bugfix
|
35
|
+
* --targets, -t option now actually works
|
36
|
+
|
37
|
+
== 0.1.5 2008-11-25
|
38
|
+
|
39
|
+
* 4 minor enhancements
|
40
|
+
* Removed 'all_targets' - just use ruby to DRY up garlic.rb
|
41
|
+
* Changed templates wrt above
|
42
|
+
* Better tabtab completions
|
43
|
+
* Updated TODO
|
44
|
+
|
45
|
+
== 0.1.4 2008-11-20
|
46
|
+
|
47
|
+
* 1 minor enhancement
|
48
|
+
* Added tabtab definitions that are in the right place
|
49
|
+
|
50
|
+
== 0.1.3 2008-11-20
|
51
|
+
|
52
|
+
* 1 minor enhancement
|
53
|
+
* Added tabtab definitions
|
54
|
+
|
55
|
+
== 0.1.2
|
56
|
+
|
57
|
+
* 2 major enhancements
|
58
|
+
* garlic CLI
|
59
|
+
* repos are now stored in ~/.garlic/repos (and this shared across multiple garlic sessions), work is in ./.garlic
|
60
|
+
|
61
|
+
== 0.1.1
|
62
|
+
|
63
|
+
* 1 major enhancement:
|
64
|
+
* freelancing-god added gem goodness
|
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2009 Ian White - ian.w.white@ardes.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
= garlic
|
2
|
+
|
3
|
+
<b>lightweight continuous integration for rails using git</b>
|
4
|
+
|
5
|
+
This is not a CI server, use cruisecontrol.rb or integrity for that. This is a simple set
|
6
|
+
of commands (or rake tasks) that let you specify a bunch of rails builds to run against, and
|
7
|
+
dependencies to install.
|
8
|
+
|
9
|
+
This is aimed at testing plugins (or apps) against multiple versions of rails,
|
10
|
+
and allows specifying other plugin dependencies (and their versions and any
|
11
|
+
setup requried).
|
12
|
+
|
13
|
+
If you want to run your specs (or whatever) against different versions of gems
|
14
|
+
that you have installed, then check out {ginger}[http://github.com/freelancing-god/ginger] by {Pat Allen}[http://github.com/freelancing-god]
|
15
|
+
|
16
|
+
Garlic works by cloning git repos for all your dependencies (so they all must be
|
17
|
+
git repos), and then using git to checkout various tags and branches to build
|
18
|
+
your app against.
|
19
|
+
|
20
|
+
Here's an example of running a plugin against 3 different rails verisons and 3 different rspec versions: {gist 28786}[http://gist.github.com/28786]
|
21
|
+
|
22
|
+
== It's still new, and not shiny yet
|
23
|
+
|
24
|
+
Please feel free to make it shinier. I'm successfully using it on most of my plugins, and I test
|
25
|
+
with rspec and cucumber.
|
26
|
+
|
27
|
+
Check out the {TODO LIST}[http://github.com/ianwhite/garlic/tree/master/Todo.txt]
|
28
|
+
|
29
|
+
== Get up and running quickly
|
30
|
+
|
31
|
+
You have a plugin and you want it tested against different versions of rails?
|
32
|
+
|
33
|
+
<b>1.</b> install garlic as a gem (see below)
|
34
|
+
|
35
|
+
<b>2.</b> cd into your (say, rspec tested) plugin directory
|
36
|
+
|
37
|
+
garlic generate rspec > garlic.rb
|
38
|
+
garlic install_repos
|
39
|
+
garlic
|
40
|
+
|
41
|
+
<b>3.</b> See what happens, edit garlic.rb to change rails versions and other stuff.
|
42
|
+
|
43
|
+
garlic --help # will probably help
|
44
|
+
|
45
|
+
== Installing
|
46
|
+
|
47
|
+
Install the garlic gem
|
48
|
+
|
49
|
+
# from rubyforge or gemcutter
|
50
|
+
sudo gem install garlic
|
51
|
+
|
52
|
+
# from github
|
53
|
+
sudo gem install ianwhite-garlic --source=http://gems.github.com
|
54
|
+
|
55
|
+
(if you want the very latest version)
|
56
|
+
|
57
|
+
git clone git://github.com/ianwhite/garlic
|
58
|
+
cd garlic
|
59
|
+
rake package
|
60
|
+
sudo gem install pkg/garlic-<code>*</code>.gem
|
61
|
+
|
62
|
+
== Example
|
63
|
+
|
64
|
+
To see garlic in action, download resources_controller_, a rails plugin that uses garlic for CI.
|
65
|
+
|
66
|
+
git clone git://github.com/ianwhite/resources_controller
|
67
|
+
|
68
|
+
|
69
|
+
run garlic
|
70
|
+
|
71
|
+
garlic all
|
72
|
+
|
73
|
+
This will clone all the required git repos (done only once), set up the target railses (done once), then run the targets.
|
74
|
+
|
75
|
+
=== Once you've committed some changes
|
76
|
+
|
77
|
+
You can prepare and run all the targets again (without fetching remote repos) by doing
|
78
|
+
|
79
|
+
garlic
|
80
|
+
|
81
|
+
This will prepare all the targets, using the current HEAD of the repos, and run the
|
82
|
+
CI task again.
|
83
|
+
|
84
|
+
=== Specifying particular targets
|
85
|
+
|
86
|
+
If you just want to run against a particular target or targets, you can use the -t option,
|
87
|
+
or if using Rake, the TARGET or TARGETS env var.
|
88
|
+
|
89
|
+
garlic -t edge
|
90
|
+
|
91
|
+
== Running Shell commands across multiple targets
|
92
|
+
|
93
|
+
Check dis out
|
94
|
+
|
95
|
+
garlic shell # {Example output}[http://gist.github.com/28795]
|
96
|
+
|
97
|
+
You can pipe any thing into garlic shell and it will execute across all of your garlic targets
|
98
|
+
|
99
|
+
== Rake tasks
|
100
|
+
|
101
|
+
If you prefer to use garlic via rake tasks, then just require 'garlic/tasks' and you'll get a bunch of em.
|
102
|
+
Once required, do rake -T to see descriptions.
|
103
|
+
|
104
|
+
== garlic workflow shell commands
|
105
|
+
|
106
|
+
If you add the following line to your .profile
|
107
|
+
|
108
|
+
source `garlic --path`/sh/garlic.sh
|
109
|
+
|
110
|
+
Then you'll get these 4 new shell commands:
|
111
|
+
|
112
|
+
gcd [target] cds into the specified target working repo
|
113
|
+
gcdp [target] cds into the specified target plugin in the working repo
|
114
|
+
gup cds back up to the garlic'd repo from within a working path
|
115
|
+
gpush [branch] from within a working repo, pushes changes back to the local garlic target, and resets
|
116
|
+
local changes in that target to HEAD.
|
117
|
+
|
118
|
+
This means you might have a workflow as follows (example is for a plugin):
|
119
|
+
|
120
|
+
# run garlic, see probs in '2-2-stable'
|
121
|
+
|
122
|
+
gcdp 2-2 # => takes you into the working repo in the '2-2-stable' target
|
123
|
+
|
124
|
+
# fix the changes, make some commits
|
125
|
+
|
126
|
+
gpush # => pushes the changes back to the enclosing garlic'd repo
|
127
|
+
gup # => go back up there
|
128
|
+
garlic # => rerun garlic to see how the changes affect the other targets
|
129
|
+
|
130
|
+
== Lend a hand
|
131
|
+
|
132
|
+
This is an early release, so there is plenty of scope for changes and improvement
|
133
|
+
If you want to lend a hand, get in touch.
|
134
|
+
|
135
|
+
(c) Ian White 2008-2009 - ian.w.white@gmail.com
|
136
|
+
MIT Licence
|
137
|
+
|
138
|
+
== Lent a hand
|
139
|
+
|
140
|
+
Thanks very much to:
|
141
|
+
|
142
|
+
* Pat Allan
|
143
|
+
* Dr Nic Williams (API suggestions)
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'
|
8
|
+
|
9
|
+
require 'garlic'
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'jeweler'
|
13
|
+
|
14
|
+
Jeweler::Tasks.new do |s|
|
15
|
+
s.name = "garlic"
|
16
|
+
s.version = Garlic::Version::String
|
17
|
+
s.summary = "Test your project across multiple versions of rails/dependencies"
|
18
|
+
s.description = "CI tool to test your project across multiple versions of rails/dependencies"
|
19
|
+
s.email = "ian.w.white@gmail.com"
|
20
|
+
s.homepage = "http://github.com/ianwhite/garlic"
|
21
|
+
s.authors = ["Ian White"]
|
22
|
+
s.rubyforge_project = 'garlic'
|
23
|
+
end
|
24
|
+
|
25
|
+
Jeweler::GemcutterTasks.new
|
26
|
+
|
27
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
28
|
+
rubyforge.doc_task = "doc"
|
29
|
+
end
|
30
|
+
|
31
|
+
namespace :release do
|
32
|
+
desc "Release current version to github, gemcutter and rubyforge"
|
33
|
+
task :all => ['release', 'gemcutter:release', 'rubyforge:release']
|
34
|
+
end
|
35
|
+
|
36
|
+
rescue LoadError
|
37
|
+
puts "Jeweler not available for gem tasks. Install it with: sudo gem install jeweler"
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
require 'hanna/rdoctask'
|
42
|
+
rescue LoadError
|
43
|
+
end
|
44
|
+
|
45
|
+
Rake::RDocTask.new(:doc) do |d|
|
46
|
+
d.options << '--all'
|
47
|
+
d.rdoc_dir = 'doc'
|
48
|
+
d.main = 'README.rdoc'
|
49
|
+
d.title = "garlic API Docs"
|
50
|
+
d.rdoc_files.include('README.rdoc', 'History.txt', 'License.txt', 'Todo.txt', 'VERSION', 'lib/**/*.rb')
|
51
|
+
end
|
52
|
+
task :rdoc => :doc
|
53
|
+
|
54
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
55
|
+
t.warning = true
|
56
|
+
end
|
57
|
+
task :default => :spec
|
data/Todo.txt
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.10
|
data/bin/garlic
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'getoptlong'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rake'
|
6
|
+
require 'garlic'
|
7
|
+
|
8
|
+
include Garlic
|
9
|
+
|
10
|
+
USAGE = "USAGE: garlic [options] [command] (try garlic --help)"
|
11
|
+
|
12
|
+
HELP = <<-end_doc
|
13
|
+
garlic - run a command in different versions of rails
|
14
|
+
|
15
|
+
USAGE: garlic [options] [command]
|
16
|
+
|
17
|
+
COMMANDS:
|
18
|
+
#{Garlic::Session.commands_with_description.map{|method, desc| " %-17s %s" % [method, desc]}.join("\n")}
|
19
|
+
|
20
|
+
The default command is "default"
|
21
|
+
|
22
|
+
OPTIONS:
|
23
|
+
--help -h You're reading it
|
24
|
+
--verbose -v Show work
|
25
|
+
--config CONFIG -c Specify a different location of garlic config
|
26
|
+
--backtrace Show ruby backtrace on error
|
27
|
+
--targets TARGETS -t Specify subset of targets comma separated or
|
28
|
+
regexp part e.g. -t 2-1,2-2
|
29
|
+
|
30
|
+
You can generate a sample garlic.rb with
|
31
|
+
garlic generate [TEMPLATE [PLUGIN_NAME]] (Available templates: #{available_templates.join(', ')})
|
32
|
+
|
33
|
+
end_doc
|
34
|
+
|
35
|
+
@verbose = false
|
36
|
+
|
37
|
+
GetoptLong.new(
|
38
|
+
['--help', '-h', GetoptLong::NO_ARGUMENT],
|
39
|
+
['--verbose', '-v', GetoptLong::NO_ARGUMENT],
|
40
|
+
['--targets', '-t', GetoptLong::REQUIRED_ARGUMENT],
|
41
|
+
['--config', '-c', GetoptLong::REQUIRED_ARGUMENT],
|
42
|
+
['--backtrace', GetoptLong::NO_ARGUMENT],
|
43
|
+
['--path', GetoptLong::NO_ARGUMENT],
|
44
|
+
['--version', GetoptLong::NO_ARGUMENT]
|
45
|
+
).each do |opt, arg|
|
46
|
+
case opt
|
47
|
+
when '--help' then STDOUT << HELP; exit true
|
48
|
+
when '--path' then puts File.dirname(File.dirname(File.expand_path(__FILE__))); exit true
|
49
|
+
when '--version' then puts Garlic::Version::String; exit true
|
50
|
+
when '--verbose' then @verbose = true
|
51
|
+
when '--config' then @config_file = arg
|
52
|
+
when '--targets' then @run_targets = arg
|
53
|
+
when '--backtrace' then @backtrace = true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
if ARGV.first == 'generate'
|
59
|
+
generate_config(*ARGV[1..-1])
|
60
|
+
else
|
61
|
+
# run a garlic command
|
62
|
+
raise "Unknown command: #{ARGV.first}" unless ARGV.empty? || Garlic::Session.commands.include?(ARGV.first)
|
63
|
+
|
64
|
+
verbose(@verbose)
|
65
|
+
|
66
|
+
# configure the garlic runner
|
67
|
+
garlic(@config_file) # load up the garlic instance
|
68
|
+
garlic.verbose = @verbose
|
69
|
+
garlic.run_targets = @run_targets
|
70
|
+
|
71
|
+
# run the command
|
72
|
+
ARGV << 'default' if ARGV.empty?
|
73
|
+
garlic.send *ARGV
|
74
|
+
end
|
75
|
+
|
76
|
+
rescue Exception => e
|
77
|
+
STDERR << "\n#{USAGE}\n\nError: #{e.message}\n\n"
|
78
|
+
raise e if @backtrace
|
79
|
+
exit false
|
80
|
+
end
|
data/garlic.gemspec
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{garlic}
|
8
|
+
s.version = "0.1.10"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ian White"]
|
12
|
+
s.date = %q{2009-10-05}
|
13
|
+
s.default_executable = %q{garlic}
|
14
|
+
s.description = %q{CI tool to test your project across multiple versions of rails/dependencies}
|
15
|
+
s.email = %q{ian.w.white@gmail.com}
|
16
|
+
s.executables = ["garlic"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".gitignore",
|
22
|
+
"History.txt",
|
23
|
+
"License.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"Todo.txt",
|
27
|
+
"VERSION",
|
28
|
+
"bin/garlic",
|
29
|
+
"garlic.gemspec",
|
30
|
+
"lib/garlic.rb",
|
31
|
+
"lib/garlic/configurator.rb",
|
32
|
+
"lib/garlic/generator.rb",
|
33
|
+
"lib/garlic/repo.rb",
|
34
|
+
"lib/garlic/session.rb",
|
35
|
+
"lib/garlic/shell.rb",
|
36
|
+
"lib/garlic/target.rb",
|
37
|
+
"lib/garlic/tasks.rb",
|
38
|
+
"lib/tabtab_definitions/garlic.rb",
|
39
|
+
"sh/garlic.sh",
|
40
|
+
"spec/garlic/repo_spec.rb",
|
41
|
+
"spec/spec_helper.rb",
|
42
|
+
"templates/default.rb",
|
43
|
+
"templates/rspec.rb",
|
44
|
+
"templates/shoulda.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/ianwhite/garlic}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubyforge_project = %q{garlic}
|
50
|
+
s.rubygems_version = %q{1.3.4}
|
51
|
+
s.summary = %q{Test your project across multiple versions of rails/dependencies}
|
52
|
+
s.test_files = [
|
53
|
+
"spec/garlic/repo_spec.rb",
|
54
|
+
"spec/spec_helper.rb"
|
55
|
+
]
|
56
|
+
|
57
|
+
if s.respond_to? :specification_version then
|
58
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
59
|
+
s.specification_version = 3
|
60
|
+
|
61
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
62
|
+
else
|
63
|
+
end
|
64
|
+
else
|
65
|
+
end
|
66
|
+
end
|
data/lib/garlic.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "garlic/session"
|
2
|
+
require "garlic/configurator"
|
3
|
+
require "garlic/repo"
|
4
|
+
require "garlic/target"
|
5
|
+
require "garlic/generator"
|
6
|
+
require "garlic/shell"
|
7
|
+
|
8
|
+
module Garlic
|
9
|
+
include Generator
|
10
|
+
|
11
|
+
module Version
|
12
|
+
String = File.read(File.dirname(File.dirname(__FILE__)) + '/VERSION').strip
|
13
|
+
Major, Minor, Patch = String.split('.').map{|i| i.to_i}
|
14
|
+
end
|
15
|
+
|
16
|
+
# return the current garlic session
|
17
|
+
def garlic(config = nil, &block)
|
18
|
+
@garlic ||= Garlic::Session.new(self)
|
19
|
+
load_config(config)
|
20
|
+
@garlic.configure(&block) if block_given?
|
21
|
+
@garlic
|
22
|
+
end
|
23
|
+
|
24
|
+
# load config from
|
25
|
+
def load_config(config = nil)
|
26
|
+
unless @garlic_config_file
|
27
|
+
@garlic_config_file = config || "garlic.rb"
|
28
|
+
unless File.exists?(@garlic_config_file)
|
29
|
+
raise "garlic requries a configuration file (can't find #{@garlic_config_file}), try:\n garlic generate [#{available_templates.join('|')}] > garlic.rb"
|
30
|
+
end
|
31
|
+
eval File.read(@garlic_config_file)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Garlic
|
2
|
+
# Configures the garlic runner in a decalarative style
|
3
|
+
class Configurator
|
4
|
+
attr_reader :garlic
|
5
|
+
|
6
|
+
def initialize(garlic, &block)
|
7
|
+
@garlic = garlic
|
8
|
+
instance_eval(&block) if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def repo(name, options = {})
|
12
|
+
options[:name] = name
|
13
|
+
options[:path] ||= "#{garlic.repo_path}/#{name}"
|
14
|
+
garlic.repos << Repo.new(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def target(name, options = {}, &block)
|
18
|
+
options[:name] = name
|
19
|
+
options[:path] = "#{garlic.work_path}/#{name_to_path(name)}"
|
20
|
+
BlockParser.new(options, [:prepare, :run], &block) if block_given?
|
21
|
+
garlic.targets << Target.new(garlic, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def respond_to?(method)
|
25
|
+
super || garlic.respond_to?("#{method}=")
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
def name_to_path(name)
|
30
|
+
name.gsub(/[^\w\d_.-]/,'_').downcase
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(attribute, value)
|
34
|
+
if garlic.respond_to?("#{attribute}=")
|
35
|
+
garlic.send("#{attribute}=", value)
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class BlockParser
|
42
|
+
attr_reader :options, :whitelist
|
43
|
+
|
44
|
+
def initialize(options, whitelist = [], &block)
|
45
|
+
@options = options
|
46
|
+
@whitelist = whitelist
|
47
|
+
instance_eval(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_missing(method, *args, &block)
|
51
|
+
if block_given? && args.empty? && (whitelist.empty? || whitelist.include?(method))
|
52
|
+
options[method.to_sym] = block
|
53
|
+
else
|
54
|
+
raise ArgumentError, "Don't know how to parse #{method} #{args.inspect unless args.empty?}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Garlic
|
4
|
+
# generate a garlic config file
|
5
|
+
module Generator
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
TEMPLATES_PATH = File.expand_path("~/.garlic/templates")
|
9
|
+
|
10
|
+
def generate_config(template = 'default', plugin = nil)
|
11
|
+
raise "unknown template: #{template}.\nUse one of #{available_templates.join(', ')} or create your own in #{TEMPLATES_PATH}" unless available_templates.include?(template)
|
12
|
+
plugin ||= File.basename(File.expand_path('.'))
|
13
|
+
puts eval("<<-EOD\n" + File.read(File.join(TEMPLATES_PATH, "#{template}.rb")) + "\nEOD")
|
14
|
+
end
|
15
|
+
|
16
|
+
def available_templates
|
17
|
+
copy_templates unless File.exists?(TEMPLATES_PATH)
|
18
|
+
Dir[File.join(TEMPLATES_PATH, '*')].map {|f| File.basename(f.sub(/.rb$/,'')) }
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
def copy_templates
|
23
|
+
mkdir_p TEMPLATES_PATH, :verbose => false
|
24
|
+
Dir[File.join(File.dirname(__FILE__), '../../templates/*.rb')].each do |file|
|
25
|
+
cp file, File.join(TEMPLATES_PATH, File.basename(file)), :verbose => false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/garlic/repo.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
module Garlic
|
2
|
+
# This class represents a local git repo
|
3
|
+
class Repo
|
4
|
+
attr_reader :url, :local, :path, :name
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
if @url = options[:url]
|
8
|
+
@url = File.expand_path(@url) unless options[:url] =~ /^\w+(:|@)/
|
9
|
+
end
|
10
|
+
|
11
|
+
@path = options[:path] or raise ArgumentError, "Repo requires a :path"
|
12
|
+
@path = File.expand_path(@path)
|
13
|
+
|
14
|
+
@local = options[:local]
|
15
|
+
@local = File.expand_path(@local) if @local
|
16
|
+
|
17
|
+
@name = options[:name] || File.basename(@path)
|
18
|
+
end
|
19
|
+
|
20
|
+
class<<self
|
21
|
+
def path?(path)
|
22
|
+
File.directory?(File.join(path, '.git'))
|
23
|
+
end
|
24
|
+
|
25
|
+
def tree_ish(options)
|
26
|
+
[:tree_ish, :tree, :branch, :tag, :commit, :sha].each do |key|
|
27
|
+
return options[key] if options[key]
|
28
|
+
end
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def head_sha(path)
|
33
|
+
`cd #{path}; git log HEAD -1 --pretty=format:\"%H\"`
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def install
|
38
|
+
if File.exists?(path)
|
39
|
+
puts "\nSkipping #{name}, as it exists"
|
40
|
+
else
|
41
|
+
puts "\nInstalling #{name}"
|
42
|
+
sh "git clone #{url}#{" --reference #{local}" if local} #{path}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def update
|
47
|
+
puts "\nUpdating #{name}..."
|
48
|
+
if Repo.path?(path)
|
49
|
+
if url
|
50
|
+
begin
|
51
|
+
checkout 'master'
|
52
|
+
cd(path) do
|
53
|
+
sh "git fetch origin", :verbose => false
|
54
|
+
sh "git pull", :verbose => false
|
55
|
+
end
|
56
|
+
rescue Exception => e
|
57
|
+
puts "\n\nIt seems there was a problem.\nTry running rake garlic:reset_repos\n\n"
|
58
|
+
raise e
|
59
|
+
end
|
60
|
+
else
|
61
|
+
puts "No url for #{name} given, so not updating"
|
62
|
+
end
|
63
|
+
elsif File.exists?(path)
|
64
|
+
raise "\nRepo #{name} (#{path}) is not a git repo.\nRemove it and run rake garlic:install_repos\n\n"
|
65
|
+
else
|
66
|
+
raise "\nRepo #{name} missing from #{path}.\nPlease run rake garlic:install_repos\n\n"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def check
|
71
|
+
if !Repo.path?(path)
|
72
|
+
raise "#{name} is missing from #{path}, or is not a git repo"
|
73
|
+
elsif url && !same_url?(origin_url)
|
74
|
+
raise "#{name}'s url has changed from #{url} to #{origin_url}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def reset
|
79
|
+
cd(path) { sh "git reset --hard master" }
|
80
|
+
checkout('master')
|
81
|
+
end
|
82
|
+
|
83
|
+
def checkout(tree_ish)
|
84
|
+
cd(path) { sh "git checkout -q #{tree_ish}", :verbose => false }
|
85
|
+
end
|
86
|
+
|
87
|
+
def export_to(export_path)
|
88
|
+
rm_rf export_path; mkdir_p export_path
|
89
|
+
cd(path) do
|
90
|
+
sh "git archive --format=tar HEAD > #{File.join(export_path, "#{name}.tar")}", :verbose => false
|
91
|
+
end
|
92
|
+
cd(export_path) do
|
93
|
+
`tar -x -f #{name}.tar`
|
94
|
+
rm "#{name}.tar"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def clone_to(clone_path)
|
99
|
+
mkdir_p File.dirname(clone_path)
|
100
|
+
cd (File.dirname(clone_path)) do
|
101
|
+
sh "git clone #{path} #{clone_path}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def origin_url
|
106
|
+
unless @origin_url
|
107
|
+
match = `cd #{path}; git remote show -n origin`.match(/URL: (.*)\n/)
|
108
|
+
@origin_url = (match && match[1])
|
109
|
+
end
|
110
|
+
@origin_url
|
111
|
+
end
|
112
|
+
|
113
|
+
def same_url?(url)
|
114
|
+
self.url.sub(/\/?(\.git)?$/, '') == url.sub(/\/?(\.git)?$/, '')
|
115
|
+
end
|
116
|
+
|
117
|
+
def head_sha
|
118
|
+
Repo.head_sha(path)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module Garlic
|
2
|
+
# this class runs the top level garlic commands
|
3
|
+
class Session
|
4
|
+
attr_reader :actor, :run_targets
|
5
|
+
attr_accessor :repos, :targets, :repo_path, :work_path, :verbose
|
6
|
+
|
7
|
+
def initialize(actor = nil, &block)
|
8
|
+
@actor = actor
|
9
|
+
self.repos = []
|
10
|
+
self.targets = []
|
11
|
+
self.work_path = ".garlic"
|
12
|
+
self.repo_path = "~/.garlic/repos"
|
13
|
+
configure(&block) if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def configure(&block)
|
17
|
+
Configurator.new(self, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def repo(name)
|
21
|
+
repos.detect {|r| r.name == name.to_s} or raise "Can't find repo: #{name}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# convert a possible string argument into an array
|
25
|
+
def run_targets=(targets)
|
26
|
+
targets = targets.split(',').map{|t| t.strip} if targets.is_a?(String)
|
27
|
+
@run_targets = targets
|
28
|
+
end
|
29
|
+
|
30
|
+
### garlic commands ###
|
31
|
+
|
32
|
+
# meta data about command methods which can be used by both rake and the cli tool
|
33
|
+
@@commands, @@command_descriptions = [], {}
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def define_command(name, desc, &block)
|
37
|
+
@@commands << name
|
38
|
+
@@command_descriptions[name] = desc
|
39
|
+
define_method name, &block
|
40
|
+
end
|
41
|
+
|
42
|
+
def commands_with_description
|
43
|
+
@@commands.map{|m| [m, @@command_descriptions[m]]}
|
44
|
+
end
|
45
|
+
|
46
|
+
def command_description(name)
|
47
|
+
@@command_descriptions[name]
|
48
|
+
end
|
49
|
+
|
50
|
+
def commands
|
51
|
+
@@command_descriptions.keys.map {|c| c.to_s}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
define_command :default, "Check repos, prepare TARGETs, and run TARGETs" do
|
56
|
+
check_repos
|
57
|
+
prepare
|
58
|
+
run
|
59
|
+
end
|
60
|
+
|
61
|
+
define_command :all, "Install and update all repos, prepare and run TARGETs" do
|
62
|
+
install_repos
|
63
|
+
update_repos
|
64
|
+
clean
|
65
|
+
prepare
|
66
|
+
run
|
67
|
+
end
|
68
|
+
|
69
|
+
define_command :install_repos, "Install required repositories" do
|
70
|
+
repos.each {|repo| repo.install}
|
71
|
+
end
|
72
|
+
|
73
|
+
define_command :update_repos, "Update repositories" do
|
74
|
+
repos.each {|repo| repo.update}
|
75
|
+
end
|
76
|
+
|
77
|
+
define_command :check_repos, "Check that repos are what they are supposed to be" do
|
78
|
+
errors = []
|
79
|
+
repos.each do |repo|
|
80
|
+
begin
|
81
|
+
repo.check
|
82
|
+
rescue Exception => e
|
83
|
+
errors << "- #{e.message}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
errors.length == 0 or raise "\n#{errors.join("\n")}\n\nPlease remove these repos and run garlic install_repos\n"
|
87
|
+
end
|
88
|
+
|
89
|
+
define_command :reset_repos, "Reset all repos to their master branch" do
|
90
|
+
repos.each {|repo| repo.reset}
|
91
|
+
end
|
92
|
+
|
93
|
+
define_command :clean, "Remove the work done by garlic" do
|
94
|
+
rm_rf work_path
|
95
|
+
end
|
96
|
+
|
97
|
+
define_command :prepare, "Prepare each garlic TARGET" do
|
98
|
+
determine_targets.each {|target| target.prepare }
|
99
|
+
end
|
100
|
+
|
101
|
+
define_command :shell, "Run shell commands from stdin across specified targets" do |*path|
|
102
|
+
shell = Shell.new(determine_targets)
|
103
|
+
shell.current_path = path.first if path.first
|
104
|
+
shell.run
|
105
|
+
end
|
106
|
+
|
107
|
+
define_command :path, "return the work dir for the specified target" do |*path_target|
|
108
|
+
self.run_targets = path_target.first if path_target.any?
|
109
|
+
puts determine_targets.first.path
|
110
|
+
end
|
111
|
+
|
112
|
+
define_command :run, "Run each garlic TARGET" do
|
113
|
+
these_targets = determine_targets
|
114
|
+
target_names, failed_names = these_targets.map{|t| t.name}, []
|
115
|
+
|
116
|
+
puts "\n#{'='*78}\nTargets: #{target_names.join(', ')}\n#{'='*78}\n"
|
117
|
+
these_targets.each do |target|
|
118
|
+
puts "\n#{'-'*78}\nTarget: #{target.name} (commit #{target.rails_sha[0..6]}, run at #{Time.now})\n#{'-'*78}\n"
|
119
|
+
begin
|
120
|
+
target.run
|
121
|
+
puts "\ntarget: #{target.name} PASS"
|
122
|
+
rescue
|
123
|
+
puts "\ntarget: #{target.name} FAIL"
|
124
|
+
failed_names << target.name
|
125
|
+
end
|
126
|
+
end
|
127
|
+
puts "\n#{'='*78}\n"
|
128
|
+
failed_names.length > 0 and raise "The following targets passed: #{(target_names - failed_names).join(', ')}.\n\nThe following targets FAILED: #{failed_names.join(', ')}.\n\n"
|
129
|
+
puts "All specified targets passed: #{target_names.join(', ')}.\n\n"
|
130
|
+
end
|
131
|
+
|
132
|
+
def respond_to?(method)
|
133
|
+
super(method) || (actor && actor.respond_to?(method))
|
134
|
+
end
|
135
|
+
|
136
|
+
protected
|
137
|
+
def method_missing(method, *args, &block)
|
138
|
+
actor ? actor.send(method, *args, &block) : super
|
139
|
+
end
|
140
|
+
|
141
|
+
def determine_targets
|
142
|
+
run_targets ? targets.select{|t| t.name =~ /(?:#{run_targets.join("|")})/i} : targets
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/garlic/shell.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
begin
|
3
|
+
require 'term/ansicolor'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
module Garlic
|
8
|
+
class Shell
|
9
|
+
include FileUtils
|
10
|
+
|
11
|
+
attr_reader :current_path
|
12
|
+
|
13
|
+
def initialize(targets)
|
14
|
+
@current_path = '.'
|
15
|
+
@targets = targets
|
16
|
+
raise "Garlic::Shell requires at least one target" if @targets.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_path=(path)
|
20
|
+
if path =~ /^(\/|\~)/
|
21
|
+
STDOUT << red << "#{path}: only relative paths allowed\n" << clear
|
22
|
+
else
|
23
|
+
full_path = File.expand_path(File.join(@targets.first.path, current_path, path))
|
24
|
+
if File.exists?(full_path)
|
25
|
+
@current_path = full_path.include?(@targets.first.path) ? full_path.sub(@targets.first.path,'') : '.'
|
26
|
+
else
|
27
|
+
STDOUT << red << "#{path}: no such directory\n" << clear
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def run
|
33
|
+
STDOUT << green << "Garlic interactive session: type shell commands\n" << clear << prompt
|
34
|
+
while (command = STDIN.gets) do
|
35
|
+
command.strip!.empty? || process(command)
|
36
|
+
STDOUT << prompt
|
37
|
+
end
|
38
|
+
rescue Interrupt
|
39
|
+
ensure
|
40
|
+
STDOUT << green << "Garlic interactive session ended\n" << clear
|
41
|
+
end
|
42
|
+
|
43
|
+
def process(command)
|
44
|
+
if command =~ /^cd (.*)$/
|
45
|
+
self.current_path = $1
|
46
|
+
else
|
47
|
+
@targets.each do |target|
|
48
|
+
cd File.join(target.path, current_path) do
|
49
|
+
STDOUT << magenta << target.name + ":\n" << clear
|
50
|
+
system(command) || STDOUT << red << "command failed\n" << clear
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
[:red, :green, :magenta, :clear].each do |colour|
|
58
|
+
define_method colour do
|
59
|
+
Term::ANSIColor.send(colour) rescue ""
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def prompt
|
64
|
+
green + "garlic:#{@current_path.sub(/^\.|\//,'')}> " + clear
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'shell'
|
2
|
+
|
3
|
+
module Garlic
|
4
|
+
class Target
|
5
|
+
attr_reader :garlic, :path, :name, :rails_repo_name, :tree_ish
|
6
|
+
|
7
|
+
def initialize(garlic, options = {})
|
8
|
+
@garlic = garlic
|
9
|
+
@tree_ish = Repo.tree_ish(options) || 'origin/master'
|
10
|
+
@rails_repo_name = options[:rails] || 'rails'
|
11
|
+
@path = options[:path] or raise ArgumentError, "Target requires a :path"
|
12
|
+
@path = File.expand_path(@path)
|
13
|
+
@name = options[:name] || File.basename(@path)
|
14
|
+
@prepare = options[:prepare]
|
15
|
+
@run = options[:run]
|
16
|
+
end
|
17
|
+
|
18
|
+
def prepare
|
19
|
+
puts "\nPreparing target #{name} (#{tree_ish})"
|
20
|
+
install_rails
|
21
|
+
runner.run(&@prepare) if @prepare
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
runner.run(&@run) if @run
|
26
|
+
end
|
27
|
+
|
28
|
+
def rails_sha
|
29
|
+
read_sha('vendor/rails')
|
30
|
+
end
|
31
|
+
|
32
|
+
def shell
|
33
|
+
unless @shell
|
34
|
+
@shell = Shell.new
|
35
|
+
@shell.verbose = false
|
36
|
+
@shell.cd path
|
37
|
+
end
|
38
|
+
@shell
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def runner
|
43
|
+
@runner ||= Target::Runner.new(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_sha(install_path)
|
47
|
+
File.read(File.join(path, install_path, '.git_sha')) rescue nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def write_sha(install_path, sha)
|
51
|
+
File.open(File.join(path, install_path, '.git_sha'), 'w+') {|f| f << sha}
|
52
|
+
end
|
53
|
+
|
54
|
+
def install_rails
|
55
|
+
rails_repo = garlic.repo(rails_repo_name)
|
56
|
+
rails_repo.checkout(tree_ish)
|
57
|
+
if File.exists?(path)
|
58
|
+
puts "Rails app for #{name} exists"
|
59
|
+
else
|
60
|
+
puts "Creating rails app for #{name}..."
|
61
|
+
`ruby #{rails_repo.path}/railties/bin/rails #{path}`
|
62
|
+
end
|
63
|
+
install_dependency(rails_repo, 'vendor/rails') { `rake rails:update` }
|
64
|
+
end
|
65
|
+
|
66
|
+
def install_dependency(repo, install_path = ".", options = {}, &block)
|
67
|
+
repo = garlic.repo(repo) unless repo.is_a?(Repo)
|
68
|
+
tree_ish = Repo.tree_ish(options)
|
69
|
+
|
70
|
+
if options[:clone]
|
71
|
+
if Repo.path?(install_path)
|
72
|
+
puts "#{install_path} exists, and is a repo"
|
73
|
+
cd(install_path) { `git fetch origin` }
|
74
|
+
else
|
75
|
+
puts "cloning #{repo.name} to #{install_path}"
|
76
|
+
repo.clone_to(File.join(path, install_path))
|
77
|
+
end
|
78
|
+
cd(install_path) { `git checkout #{tree_ish || repo.head_sha}` }
|
79
|
+
|
80
|
+
else
|
81
|
+
old_tree_ish = repo.head_sha
|
82
|
+
repo.checkout(tree_ish) if tree_ish
|
83
|
+
if read_sha(install_path) == repo.head_sha
|
84
|
+
puts "#{install_path} is up to date at #{tree_ish || repo.head_sha[0..6]}"
|
85
|
+
else
|
86
|
+
puts "#{install_path} needs update to #{tree_ish || repo.head_sha[0..6]}, exporting archive from #{repo.name}..."
|
87
|
+
repo.export_to(File.join(path, install_path))
|
88
|
+
cd(path) { garlic.instance_eval(&block) } if block_given?
|
89
|
+
write_sha(install_path, repo.head_sha)
|
90
|
+
end
|
91
|
+
repo.checkout(old_tree_ish) if tree_ish
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
class Runner
|
97
|
+
attr_reader :target
|
98
|
+
|
99
|
+
def initialize(target)
|
100
|
+
@target = target
|
101
|
+
end
|
102
|
+
|
103
|
+
def run(&block)
|
104
|
+
cd target.path do
|
105
|
+
instance_eval(&block)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def method_missing(method, *args, &block)
|
110
|
+
target.garlic.send(method, *args, &block)
|
111
|
+
end
|
112
|
+
|
113
|
+
def respond_to?(method)
|
114
|
+
super(method) || target.garlic.respond_to?(method)
|
115
|
+
end
|
116
|
+
|
117
|
+
def plugin(plugin, options = {}, &block)
|
118
|
+
target.send(:install_dependency, plugin, "vendor/plugins/#{options[:as] || plugin}", options, &block)
|
119
|
+
end
|
120
|
+
|
121
|
+
def dependency(repo, dest, options = {}, &block)
|
122
|
+
target.send(:install_dependency, repo, dest, options, &block)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/garlic/tasks.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'garlic'))
|
2
|
+
|
3
|
+
include Garlic
|
4
|
+
|
5
|
+
# configure the garlic runner
|
6
|
+
garlic ENV['CONFIG'] do
|
7
|
+
verbose ['true', 'yes', '1'].include?(ENV['VERBOSE'])
|
8
|
+
run_targets ENV['TARGETS'] || ENV['TARGET']
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Run garlic:default (CONFIG=path, TARGETS=list, VERBOSE=true)"
|
12
|
+
task :garlic do
|
13
|
+
garlic.default
|
14
|
+
end
|
15
|
+
|
16
|
+
namespace :garlic do
|
17
|
+
Garlic::Session.commands_with_description.each do |command, description|
|
18
|
+
desc description
|
19
|
+
task command do
|
20
|
+
garlic.send command
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "garlic/session"
|
2
|
+
require "garlic/generator"
|
3
|
+
|
4
|
+
TabTab::Definition.register('garlic', :import => '--help') do |g|
|
5
|
+
Garlic::Session.commands.each do |c|
|
6
|
+
g.command c
|
7
|
+
end
|
8
|
+
|
9
|
+
g.command :generate do
|
10
|
+
class << self
|
11
|
+
include Garlic::Generator
|
12
|
+
end
|
13
|
+
available_templates
|
14
|
+
end
|
15
|
+
end
|
data/sh/garlic.sh
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# garlic shell helpers
|
2
|
+
|
3
|
+
# cd into the work path of a garlic target
|
4
|
+
gcd ()
|
5
|
+
{
|
6
|
+
cd `garlic path $1`
|
7
|
+
}
|
8
|
+
|
9
|
+
# cd into probable plugin dir of a garlic target
|
10
|
+
gcdp ()
|
11
|
+
{
|
12
|
+
here=`pwd | sed 's/.*\///'`
|
13
|
+
cd `garlic path $1`/vendor/plugins/$here
|
14
|
+
}
|
15
|
+
|
16
|
+
# cd back up to enclosing garlic project
|
17
|
+
gup ()
|
18
|
+
{
|
19
|
+
cd `pwd | sed 's/\.garlic.*//'`
|
20
|
+
}
|
21
|
+
|
22
|
+
# push changes back to local garlic origin, resetting the origin
|
23
|
+
gpush ()
|
24
|
+
{
|
25
|
+
if [ `pwd | sed 's/\.garlic//'` == `pwd` ]; then
|
26
|
+
echo "gpush can only be used in a garlic work repo";
|
27
|
+
else
|
28
|
+
git push origin $1 2>&1 | grep -v warning;
|
29
|
+
here=`pwd`;
|
30
|
+
gup;
|
31
|
+
git reset --hard;
|
32
|
+
cd $here;
|
33
|
+
fi
|
34
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Garlic::Repo do
|
4
|
+
describe "new(:url => 'some/local/repo', :path => 'some/dest')" do
|
5
|
+
before { @repo = Garlic::Repo.new(:url => 'some/local/repo', :path => 'some/dest') }
|
6
|
+
|
7
|
+
it "should expand the path" do
|
8
|
+
@repo.path.should == File.expand_path('some/dest')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should expand the url" do
|
12
|
+
@repo.url.should == File.expand_path('some/local/repo')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have name == 'dest' (basename of path)" do
|
16
|
+
@repo.name.should == 'dest'
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#install' do
|
20
|
+
before do
|
21
|
+
@repo.stub!(:puts) # silence!
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should 'git clone <repo> <dest>" do
|
25
|
+
@repo.should_receive(:sh).with("git clone #{@repo.url} #{@repo.path}")
|
26
|
+
@repo.install
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "new(:url => 'git://remote/repo', :path => 'some/dest')" do
|
32
|
+
before { @repo = Garlic::Repo.new(:url => 'git://remote/repo', :path => 'some/dest') }
|
33
|
+
|
34
|
+
it "should NOT expand the url" do
|
35
|
+
@repo.url == 'git://remote/repo'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# typical vanilla garlic configuration
|
2
|
+
|
3
|
+
garlic do
|
4
|
+
# this plugin
|
5
|
+
repo "#{plugin}", :path => '.'
|
6
|
+
|
7
|
+
# other repos
|
8
|
+
repo "rails", :url => "git://github.com/rails/rails"
|
9
|
+
|
10
|
+
# target railses
|
11
|
+
['master', '2-3-stable', '2-2-stable', '2-1-stable', '2-0-stable'].each do |rails|
|
12
|
+
|
13
|
+
# declare how to prepare, and run each CI target
|
14
|
+
target rails, :tree_ish => "origin/#{rails}" do
|
15
|
+
prepare do
|
16
|
+
plugin "#{plugin}", :clone => true # so we can work in targets
|
17
|
+
end
|
18
|
+
|
19
|
+
run do
|
20
|
+
cd "vendor/plugins/#{plugin}" do
|
21
|
+
sh "rake"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/templates/rspec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# typical rspec garlic configuration
|
2
|
+
|
3
|
+
garlic do
|
4
|
+
# this plugin
|
5
|
+
repo "#{plugin}", :path => '.'
|
6
|
+
|
7
|
+
# other repos
|
8
|
+
repo "rails", :url => "git://github.com/rails/rails"
|
9
|
+
repo "rspec", :url => "git://github.com/dchelimsky/rspec"
|
10
|
+
repo "rspec-rails", :url => "git://github.com/dchelimsky/rspec-rails"
|
11
|
+
|
12
|
+
# target railses
|
13
|
+
['master', '2-3-stable', '2-2-stable', '2-1-stable', '2-0-stable'].each do |rails|
|
14
|
+
|
15
|
+
# declare how to prepare, and run each CI target
|
16
|
+
target rails, :tree_ish => "origin/#{rails}" do
|
17
|
+
prepare do
|
18
|
+
plugin "#{plugin}", :clone => true # so we can work in targets
|
19
|
+
plugin "rspec"
|
20
|
+
plugin "rspec-rails" do
|
21
|
+
`script/generate rspec -f`
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
run do
|
26
|
+
cd "vendor/plugins/#{plugin}" do
|
27
|
+
sh "rake"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# typical shoulda garlic configuration
|
2
|
+
|
3
|
+
garlic do
|
4
|
+
# this plugin
|
5
|
+
repo "#{plugin}", :path => '.'
|
6
|
+
|
7
|
+
# other repos
|
8
|
+
repo "rails", :url => "git://github.com/rails/rails"
|
9
|
+
repo "shoulda", :url => "git://github.com/thoughtbot/shoulda"
|
10
|
+
|
11
|
+
# target railses
|
12
|
+
['master', '2-3-stable', '2-2-stable', '2-1-stable', '2-0-stable'].each do |rails|
|
13
|
+
|
14
|
+
# declare how to prepare, and run each CI target
|
15
|
+
target rails, :tree_ish => "origin/#{rails}" do
|
16
|
+
prepare do
|
17
|
+
plugin "#{plugin}", :clone => true # so we can work in targets
|
18
|
+
plugin "shoulda"
|
19
|
+
end
|
20
|
+
|
21
|
+
run do
|
22
|
+
cd "vendor/plugins/#{plugin}" do
|
23
|
+
sh "rake"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: garlic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.10
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ian White
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-05 00:00:00 -04:00
|
13
|
+
default_executable: garlic
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: CI tool to test your project across multiple versions of rails/dependencies
|
17
|
+
email: ian.w.white@gmail.com
|
18
|
+
executables:
|
19
|
+
- garlic
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- History.txt
|
27
|
+
- License.txt
|
28
|
+
- README.rdoc
|
29
|
+
- Rakefile
|
30
|
+
- Todo.txt
|
31
|
+
- VERSION
|
32
|
+
- bin/garlic
|
33
|
+
- garlic.gemspec
|
34
|
+
- lib/garlic.rb
|
35
|
+
- lib/garlic/configurator.rb
|
36
|
+
- lib/garlic/generator.rb
|
37
|
+
- lib/garlic/repo.rb
|
38
|
+
- lib/garlic/session.rb
|
39
|
+
- lib/garlic/shell.rb
|
40
|
+
- lib/garlic/target.rb
|
41
|
+
- lib/garlic/tasks.rb
|
42
|
+
- lib/tabtab_definitions/garlic.rb
|
43
|
+
- sh/garlic.sh
|
44
|
+
- spec/garlic/repo_spec.rb
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
- templates/default.rb
|
47
|
+
- templates/rspec.rb
|
48
|
+
- templates/shoulda.rb
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/ianwhite/garlic
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options:
|
55
|
+
- --charset=UTF-8
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project: garlic
|
73
|
+
rubygems_version: 1.3.4
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Test your project across multiple versions of rails/dependencies
|
77
|
+
test_files:
|
78
|
+
- spec/garlic/repo_spec.rb
|
79
|
+
- spec/spec_helper.rb
|