bard 0.3.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.
- data/.document +5 -0
- data/.gitignore +6 -0
- data/.gitmodules +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +25 -0
- data/Rakefile +92 -0
- data/VERSION +1 -0
- data/bard.gemspec +92 -0
- data/bin/bard +17 -0
- data/features/bard_pull.feature +82 -0
- data/features/bard_push.feature +89 -0
- data/features/step_definitions/git_steps.rb +55 -0
- data/features/step_definitions/global_steps.rb +41 -0
- data/features/step_definitions/rails_steps.rb +104 -0
- data/features/step_definitions/submodule_steps.rb +172 -0
- data/features/support/env.rb +9 -0
- data/features/support/grit_ext.rb +16 -0
- data/features/support/io.rb +27 -0
- data/lib/bard.rb +108 -0
- data/lib/bard/git.rb +47 -0
- data/lib/bard/io.rb +22 -0
- data/spec/bard_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- metadata +169 -0
data/.document
ADDED
data/.gitmodules
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Micah Geisel
|
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,25 @@
|
|
1
|
+
= BARD gem
|
2
|
+
|
3
|
+
This immaculate work of engineering genius allows mere mortals to collaborate with beings of transcendent intelligence like Micah, Michael, and Nick.
|
4
|
+
|
5
|
+
== Requirements
|
6
|
+
gem install thor
|
7
|
+
gem install systemu
|
8
|
+
gem install term-ansicolor
|
9
|
+
gem install git_remote_branch
|
10
|
+
git --version >= 1.6.0
|
11
|
+
|
12
|
+
== Note on Patches/Pull Requests
|
13
|
+
|
14
|
+
* Fork the project.
|
15
|
+
* Make your feature addition or bug fix.
|
16
|
+
* Add tests for it. This is important so I don't break it in a
|
17
|
+
future version unintentionally.
|
18
|
+
* Commit, do not mess with rakefile, version, or history.
|
19
|
+
(if you want to have your own version, that is fine but
|
20
|
+
bump version in a commit by itself I can ignore when I pull)
|
21
|
+
* Send me a pull request. Bonus points for topic branches.
|
22
|
+
|
23
|
+
== Copyright
|
24
|
+
|
25
|
+
Copyright (c) 2009 Micah Geisel. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "bard"
|
8
|
+
gem.summary = %Q{Tools for collaborating with Bot and Rose Design.}
|
9
|
+
gem.description = %Q{This immaculate work of engineering genius allows mere mortals to collaborate with beings of transcendent intelligence like Micah, Michael, and Nick.}
|
10
|
+
gem.email = "info@botandrose.com"
|
11
|
+
gem.homepage = "http://github.com/botandrose/bard"
|
12
|
+
gem.authors = ["Micah Geisel", "Nick Hogle"]
|
13
|
+
gem.add_development_dependency "ruby-debug"
|
14
|
+
gem.add_development_dependency "rspec"
|
15
|
+
gem.add_development_dependency "cucumber"
|
16
|
+
gem.add_dependency(%q<rubygems-update>, [">= 1.3.2"])
|
17
|
+
gem.add_dependency(%q<thor>, [">= 0.11.7"])
|
18
|
+
gem.add_dependency(%q<grit>, [">= 1.1.1"])
|
19
|
+
gem.add_dependency(%q<git_remote_branch>, [">= 0.3.0"])
|
20
|
+
gem.add_dependency(%q<systemu>, [">= 1.2.0"])
|
21
|
+
gem.add_dependency(%q<term-ansicolor>, [">= 1.0.3"])
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'spec/rake/spectask'
|
29
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
35
|
+
spec.libs << 'lib' << 'spec'
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :spec => :check_dependencies
|
41
|
+
|
42
|
+
begin
|
43
|
+
require 'cucumber/rake/task'
|
44
|
+
Cucumber::Rake::Task.new(:features)
|
45
|
+
|
46
|
+
task :features => :check_dependencies
|
47
|
+
rescue LoadError
|
48
|
+
task :features do
|
49
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
require 'reek/rake_task'
|
55
|
+
Reek::RakeTask.new do |t|
|
56
|
+
t.fail_on_error = true
|
57
|
+
t.verbose = false
|
58
|
+
t.source_files = 'lib/**/*.rb'
|
59
|
+
end
|
60
|
+
rescue LoadError
|
61
|
+
task :reek do
|
62
|
+
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
begin
|
67
|
+
require 'roodi'
|
68
|
+
require 'roodi_task'
|
69
|
+
RoodiTask.new do |t|
|
70
|
+
t.verbose = false
|
71
|
+
end
|
72
|
+
rescue LoadError
|
73
|
+
task :roodi do
|
74
|
+
abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
task :default => :spec
|
79
|
+
|
80
|
+
require 'rake/rdoctask'
|
81
|
+
Rake::RDocTask.new do |rdoc|
|
82
|
+
if File.exist?('VERSION')
|
83
|
+
version = File.read('VERSION')
|
84
|
+
else
|
85
|
+
version = ""
|
86
|
+
end
|
87
|
+
|
88
|
+
rdoc.rdoc_dir = 'rdoc'
|
89
|
+
rdoc.title = "bard #{version}"
|
90
|
+
rdoc.rdoc_files.include('README*')
|
91
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
92
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.1
|
data/bard.gemspec
ADDED
@@ -0,0 +1,92 @@
|
|
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{bard}
|
8
|
+
s.version = "0.3.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Micah Geisel", "Nick Hogle"]
|
12
|
+
s.date = %q{2009-09-30}
|
13
|
+
s.default_executable = %q{bard}
|
14
|
+
s.description = %q{This immaculate work of engineering genius allows mere mortals to collaborate with beings of transcendent intelligence like Micah, Michael, and Nick.}
|
15
|
+
s.email = %q{info@botandrose.com}
|
16
|
+
s.executables = ["bard"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
".gitmodules",
|
25
|
+
"LICENSE",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"bard.gemspec",
|
30
|
+
"bin/bard",
|
31
|
+
"features/bard_pull.feature",
|
32
|
+
"features/bard_push.feature",
|
33
|
+
"features/step_definitions/git_steps.rb",
|
34
|
+
"features/step_definitions/global_steps.rb",
|
35
|
+
"features/step_definitions/rails_steps.rb",
|
36
|
+
"features/step_definitions/submodule_steps.rb",
|
37
|
+
"features/support/env.rb",
|
38
|
+
"features/support/grit_ext.rb",
|
39
|
+
"features/support/io.rb",
|
40
|
+
"lib/bard.rb",
|
41
|
+
"lib/bard/git.rb",
|
42
|
+
"lib/bard/io.rb",
|
43
|
+
"spec/bard_spec.rb",
|
44
|
+
"spec/spec_helper.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/botandrose/bard}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.4}
|
50
|
+
s.summary = %q{Tools for collaborating with Bot and Rose Design.}
|
51
|
+
s.test_files = [
|
52
|
+
"spec/spec_helper.rb",
|
53
|
+
"spec/bard_spec.rb"
|
54
|
+
]
|
55
|
+
|
56
|
+
if s.respond_to? :specification_version then
|
57
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
58
|
+
s.specification_version = 3
|
59
|
+
|
60
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
61
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
63
|
+
s.add_development_dependency(%q<cucumber>, [">= 0"])
|
64
|
+
s.add_runtime_dependency(%q<rubygems-update>, [">= 1.3.2"])
|
65
|
+
s.add_runtime_dependency(%q<thor>, [">= 0.11.7"])
|
66
|
+
s.add_runtime_dependency(%q<grit>, [">= 1.1.1"])
|
67
|
+
s.add_runtime_dependency(%q<git_remote_branch>, [">= 0.3.0"])
|
68
|
+
s.add_runtime_dependency(%q<systemu>, [">= 1.2.0"])
|
69
|
+
s.add_runtime_dependency(%q<term-ansicolor>, [">= 1.0.3"])
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
72
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
73
|
+
s.add_dependency(%q<cucumber>, [">= 0"])
|
74
|
+
s.add_dependency(%q<rubygems-update>, [">= 1.3.2"])
|
75
|
+
s.add_dependency(%q<thor>, [">= 0.11.7"])
|
76
|
+
s.add_dependency(%q<grit>, [">= 1.1.1"])
|
77
|
+
s.add_dependency(%q<git_remote_branch>, [">= 0.3.0"])
|
78
|
+
s.add_dependency(%q<systemu>, [">= 1.2.0"])
|
79
|
+
s.add_dependency(%q<term-ansicolor>, [">= 1.0.3"])
|
80
|
+
end
|
81
|
+
else
|
82
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
83
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
84
|
+
s.add_dependency(%q<cucumber>, [">= 0"])
|
85
|
+
s.add_dependency(%q<rubygems-update>, [">= 1.3.2"])
|
86
|
+
s.add_dependency(%q<thor>, [">= 0.11.7"])
|
87
|
+
s.add_dependency(%q<grit>, [">= 1.1.1"])
|
88
|
+
s.add_dependency(%q<git_remote_branch>, [">= 0.3.0"])
|
89
|
+
s.add_dependency(%q<systemu>, [">= 1.2.0"])
|
90
|
+
s.add_dependency(%q<term-ansicolor>, [">= 1.0.3"])
|
91
|
+
end
|
92
|
+
end
|
data/bin/bard
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- mode: ruby -*-
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'thor'
|
6
|
+
require 'thor/runner'
|
7
|
+
|
8
|
+
THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
9
|
+
require File.join(File.dirname(THIS_FILE), '..', 'lib', 'bard')
|
10
|
+
|
11
|
+
args = ARGV
|
12
|
+
if args[0] =~ /^[a-z]/i
|
13
|
+
args[0] = "bard:#{args[0]}"
|
14
|
+
else
|
15
|
+
args.unshift "bard"
|
16
|
+
end
|
17
|
+
Thor::Runner.start args
|
@@ -0,0 +1,82 @@
|
|
1
|
+
Feature: bard pull
|
2
|
+
Background:
|
3
|
+
Given a shared rails project
|
4
|
+
|
5
|
+
Scenario: Pulling down the latest changes from the remote integration branch
|
6
|
+
Given the remote integration branch has had a commit since I last pulled
|
7
|
+
When I type "bard pull"
|
8
|
+
Then the "integration" branch should match the "origin/integration" branch
|
9
|
+
|
10
|
+
Scenario: Pulling down when the latest changes include a submodule addition
|
11
|
+
Given the remote integration branch has had a commit that includes a new submodule
|
12
|
+
When I type "bard pull"
|
13
|
+
Then the "integration" branch should match the "origin/integration" branch
|
14
|
+
And there should be one new submodule
|
15
|
+
And the submodule should be checked out
|
16
|
+
|
17
|
+
Scenario: Pulling down when the latest changes include a submodule update
|
18
|
+
Given a submodule
|
19
|
+
And the remote integration branch has had a commit that includes a submodule update
|
20
|
+
When I type "bard pull"
|
21
|
+
Then the "integration" branch should match the "origin/integration" branch
|
22
|
+
And the submodule should be updated
|
23
|
+
|
24
|
+
Scenario: Pulling down when the latest changes include a submodule url change
|
25
|
+
Given a submodule
|
26
|
+
And the remote integration branch has had a commit that includes a submodule url change
|
27
|
+
When I type "bard pull"
|
28
|
+
Then the "integration" branch should match the "origin/integration" branch
|
29
|
+
And the submodule url should be changed
|
30
|
+
And the submodule should be checked out
|
31
|
+
|
32
|
+
# TODO
|
33
|
+
#Scenario: Pulling down when the latest changes include a submodule deletion
|
34
|
+
# Given a submodule
|
35
|
+
# And the remote integration branch has had a commit that includes a submodule deletion
|
36
|
+
# When I type "bard pull"
|
37
|
+
# Then the "integration" branch should match the "origin/integration" branch
|
38
|
+
# And the submodule should be deleted
|
39
|
+
|
40
|
+
Scenario: Pulling latest changes from the remote integration branch after committing locally
|
41
|
+
Given the remote integration branch has had a commit since I last pulled
|
42
|
+
And I have committed a set of changes to my local integration branch
|
43
|
+
When I type "bard pull"
|
44
|
+
Then I should see the warning "Someone has pushed some changes"
|
45
|
+
And the "integration" branch should be a fast-forward from the "origin/integration" branch
|
46
|
+
|
47
|
+
Scenario: Trying to bard pull with a dirty working directory
|
48
|
+
Given the remote integration branch has had a commit since I last pulled
|
49
|
+
And a dirty working directory
|
50
|
+
When I type "bard pull"
|
51
|
+
Then I should see the fatal error "You have uncommitted changes!"
|
52
|
+
And the "integration" branch should not match the "origin/integration" branch
|
53
|
+
|
54
|
+
Scenario: Trying to bard pull when not on the integration branch
|
55
|
+
Given the remote integration branch has had a commit since I last pulled
|
56
|
+
And I am on a non-integration branch
|
57
|
+
When I type "bard pull"
|
58
|
+
Then I should see the fatal error "not on the integration branch"
|
59
|
+
And the "integration" branch should not match the "origin/integration" branch
|
60
|
+
|
61
|
+
Scenario: Pulling in a change that includes a migration on a dev machine
|
62
|
+
Given the remote integration branch has had a commit that includes a new migration
|
63
|
+
And I have a development environment set up locally
|
64
|
+
When I type "bard pull"
|
65
|
+
Then the development database should include that migration
|
66
|
+
|
67
|
+
Scenario: Pulling in a change that includes a migration on a dev and testing machine
|
68
|
+
Given the remote integration branch has had a commit that includes a new migration
|
69
|
+
And I have development and test environments set up locally
|
70
|
+
When I type "bard pull"
|
71
|
+
Then both the development and test databases should include that migration
|
72
|
+
|
73
|
+
Scenario: Pulling in a change that includes a gem dependency change
|
74
|
+
Given I dont have the test gem installed
|
75
|
+
And the remote integration branch has had a commit that adds the test gem as a dependency
|
76
|
+
When I type "bard pull"
|
77
|
+
Then the test gem should be installed
|
78
|
+
|
79
|
+
Scenario: Pulling in a change should restart the rails server
|
80
|
+
Given the remote integration branch has had a commit since I last pulled
|
81
|
+
When I type "bard pull"
|
82
|
+
Then passenger should have been restarted
|
@@ -0,0 +1,89 @@
|
|
1
|
+
Feature: bard push
|
2
|
+
Background:
|
3
|
+
Given a shared rails project
|
4
|
+
|
5
|
+
Scenario: Uploading local changes onto the remote integration branch
|
6
|
+
Given I have committed a set of changes to my local integration branch
|
7
|
+
When I type "bard push"
|
8
|
+
Then the "integration" branch should match the "origin/integration" branch
|
9
|
+
|
10
|
+
Scenario: Pushing a change that includes a migration
|
11
|
+
Given I have committed a set of changes that includes a new migration
|
12
|
+
And the staging server has a staging and test environment set up
|
13
|
+
When I type "bard push"
|
14
|
+
Then the both the staging and test databases should include that migration
|
15
|
+
|
16
|
+
Scenario: Pushing a change that includes a gem dependency change
|
17
|
+
Given I dont have the test gem installed
|
18
|
+
And I have committed a set of changes that adds the test gem as a dependency
|
19
|
+
When I type "bard push"
|
20
|
+
Then the test gem should be installed
|
21
|
+
|
22
|
+
Scenario: Pushing a change should advance the staging HEAD and restart the staging rails server
|
23
|
+
Given I have committed a set of changes to my local integration branch
|
24
|
+
When I type "bard push"
|
25
|
+
Then the remote directory should not be dirty
|
26
|
+
And the staging passenger should have been restarted
|
27
|
+
|
28
|
+
Scenario: Pushing a change that includes a submodule addition
|
29
|
+
Given I have committed a set of changes that includes a new submodule
|
30
|
+
When I type "bard push"
|
31
|
+
Then there should be one new submodule on the remote
|
32
|
+
And the remote submodule should be checked out
|
33
|
+
|
34
|
+
Scenario: Pushing a change that includes a submodule update
|
35
|
+
Given a submodule
|
36
|
+
And I have committed a set of changes that includes a submodule update
|
37
|
+
When I type "bard push"
|
38
|
+
Then the remote submodule should be updated
|
39
|
+
|
40
|
+
Scenario: Pushing a change that includes a submodule url change
|
41
|
+
Given a submodule
|
42
|
+
Given I have committed a set of changes that includes a submodule url change
|
43
|
+
When I type "bard push"
|
44
|
+
Then the remote submodule url should be changed
|
45
|
+
And the remote submodule should be checked out
|
46
|
+
|
47
|
+
# TODO
|
48
|
+
#Scenario: Pushing a change that includes a submodule deletion
|
49
|
+
# Given a submodule
|
50
|
+
# Given I have committed a set of changes that includes a submodule deletion
|
51
|
+
# When I type "bard push"
|
52
|
+
# Then the remote submodule should be deleted
|
53
|
+
|
54
|
+
Scenario: Trying to bard push when not on the integration branch
|
55
|
+
Given I have committed a set of changes to my local integration branch
|
56
|
+
And I am on a non-integration branch
|
57
|
+
When I type "bard push"
|
58
|
+
Then I should see the fatal error "not on the integration branch"
|
59
|
+
And the "integration" branch should not match the "origin/integration" branch
|
60
|
+
|
61
|
+
Scenario: Trying to bard push with a dirty working directory
|
62
|
+
Given I have committed a set of changes to my local integration branch
|
63
|
+
And a dirty working directory
|
64
|
+
When I type "bard push"
|
65
|
+
Then I should see the fatal error "You have uncommitted changes!"
|
66
|
+
And the "integration" branch should not match the "origin/integration" branch
|
67
|
+
|
68
|
+
Scenario: Trying to bard push with a non-fast-foward changeset
|
69
|
+
Given I have committed a set of changes to my local integration branch
|
70
|
+
And the remote integration branch has had a commit since I last pulled
|
71
|
+
When I type "bard push"
|
72
|
+
Then I should see the fatal error "Someone has pushed some changes"
|
73
|
+
And the "integration" branch should not match the "origin/integration" branch
|
74
|
+
|
75
|
+
Scenario: Trying to bard push with an uncommitted change to a submodule
|
76
|
+
Given a submodule
|
77
|
+
And I have committed a set of changes to my local integration branch
|
78
|
+
And the submodule working directory is dirty
|
79
|
+
When I type "bard push"
|
80
|
+
Then I should see the fatal error "Micah"
|
81
|
+
And the "integration" branch should not match the "origin/integration" branch
|
82
|
+
|
83
|
+
Scenario: Trying to bard push with a committed but unpushed change to a submodule
|
84
|
+
Given a submodule
|
85
|
+
And I have committed a set of changes to the submodule
|
86
|
+
And I have committed a set of changes to my local integration branch
|
87
|
+
When I type "bard push"
|
88
|
+
Then I should see the fatal error "Micah"
|
89
|
+
And the "integration" branch should not match the "origin/integration" branch
|
@@ -0,0 +1,55 @@
|
|
1
|
+
Given /^I am on a non\-integration branch$/ do
|
2
|
+
type "git checkout -b bad_bad_bad"
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^a dirty working directory$/ do
|
6
|
+
File.open("dirty_file", "w") { |f| f.puts "dirty dirty" }
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^I have committed a set of changes to my local integration branch$/ do
|
10
|
+
type "echo 'fuck shit' > fuck_file"
|
11
|
+
type "git add ."
|
12
|
+
type "git commit -am'test commit to local integration branch.'"
|
13
|
+
end
|
14
|
+
|
15
|
+
Given /^the remote integration branch has had a commit since I last pulled$/ do
|
16
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
17
|
+
type "git checkout integration"
|
18
|
+
type "echo 'zomg' > origin_change_file"
|
19
|
+
type "git add ."
|
20
|
+
type "git commit -am 'testing origin change'"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^the directory should not be dirty$/ do
|
25
|
+
type("git status").should include "working directory clean"
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^the remote directory should not be dirty$/ do
|
29
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
30
|
+
type("git status").should include "working directory clean"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Then /^I should be on the "([^\"]*)" branch$/ do |branch|
|
35
|
+
@repo.head.name.should == branch
|
36
|
+
end
|
37
|
+
|
38
|
+
Then /^there should not be a "([^\"]*)" branch$/ do |branch_name|
|
39
|
+
@repo.branches.any? { |branch| branch.name == branch_name }
|
40
|
+
end
|
41
|
+
|
42
|
+
Then /^the "([^\"]*)" branch (should|should not) match the "([^\"]*)" branch$/ do |local_branch, which, remote_branch|
|
43
|
+
type "git fetch origin"
|
44
|
+
local_sha = @repo.commits(local_branch).first.id
|
45
|
+
remote_sha = @repo.commits(remote_branch).first.id
|
46
|
+
which = which.gsub(/ /, '_').to_sym
|
47
|
+
local_sha.send(which) == remote_sha
|
48
|
+
end
|
49
|
+
|
50
|
+
Then /^the "([^\"]*)" branch should be a fast\-forward from the "([^\"]*)" branch$/ do |local_branch, remote_branch|
|
51
|
+
local_sha = @repo.commits(local_branch).first.id
|
52
|
+
remote_sha = @repo.commits(remote_branch).first.id
|
53
|
+
common_ancestor = @repo.find_common_ancestor local_sha, remote_sha
|
54
|
+
common_ancestor.should == remote_sha
|
55
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
Given /^a shared rails project$/ do
|
2
|
+
# TEARDOWN
|
3
|
+
Dir.chdir ROOT
|
4
|
+
type "rm -rf tmp"
|
5
|
+
|
6
|
+
# SETUP
|
7
|
+
Dir.chdir ROOT
|
8
|
+
Dir.mkdir 'tmp'
|
9
|
+
type "cp -R fixtures/repo tmp/origin"
|
10
|
+
Dir.chdir 'tmp/origin' do
|
11
|
+
File.open ".git/hooks/post-receive", "w" do |f|
|
12
|
+
f.puts <<-BASH
|
13
|
+
#!/bin/bash
|
14
|
+
RAILS_ENV=staging #{ROOT}/bin/bard stage
|
15
|
+
BASH
|
16
|
+
f.chmod 0775
|
17
|
+
end
|
18
|
+
type "cp config/database.yml.sample config/database.yml"
|
19
|
+
type "git checkout -b integration"
|
20
|
+
end
|
21
|
+
type "cp -R fixtures/repo tmp/submodule"
|
22
|
+
type "cp -R fixtures/repo tmp/submodule2"
|
23
|
+
type "git clone tmp/origin tmp/local"
|
24
|
+
Dir.chdir 'tmp/local'
|
25
|
+
@repo = Grit::Repo.new "."
|
26
|
+
type "grb fetch integration"
|
27
|
+
type "git checkout integration"
|
28
|
+
type "cp config/database.yml.sample config/database.yml"
|
29
|
+
end
|
30
|
+
|
31
|
+
When /^I type "([^\"]*)"$/ do |command|
|
32
|
+
type command
|
33
|
+
end
|
34
|
+
|
35
|
+
Then /^I should see the fatal error "([^\"]*)"$/ do |error_message|
|
36
|
+
@stderr.should include(error_message)
|
37
|
+
end
|
38
|
+
|
39
|
+
Then /^I should see the warning "([^\"]*)"$/ do |warning_message|
|
40
|
+
@stderr.should include(warning_message)
|
41
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
Given /^I have committed a set of changes that includes a new migration$/ do
|
2
|
+
Dir.chdir "#{ROOT}/tmp/local" do
|
3
|
+
type "script/generate migration test_migration"
|
4
|
+
type "git add ."
|
5
|
+
type "git commit -am'added test migration.'"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^the remote integration branch has had a commit that includes a new migration$/ do
|
10
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
11
|
+
type "script/generate migration test_migration"
|
12
|
+
type "git add ."
|
13
|
+
type "git commit -am'added test migration.'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /^I have a development environment set up locally$/ do
|
18
|
+
Dir.chdir "#{ROOT}/tmp/local" do
|
19
|
+
type "rake db:create"
|
20
|
+
type "rake db:migrate"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Given /^the staging server has a staging and test environment set up$/ do
|
25
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
26
|
+
type "rake db:create RAILS_ENV=staging && rake db:create RAILS_ENV=test"
|
27
|
+
type "rake db:migrate RAILS_ENV=staging && rake db:migrate RAILS_ENV=test"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Given /^I have development and test environments set up locally$/ do
|
32
|
+
Dir.chdir "#{ROOT}/tmp/local" do
|
33
|
+
type "rake db:create && rake db:create RAILS_ENV=test"
|
34
|
+
type "rake db:migrate && rake db:migrate RAILS_ENV=test"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Then /^the development database should include that migration$/ do
|
39
|
+
Dir.chdir "#{ROOT}/tmp/local" do
|
40
|
+
db_version = type("rake db:version")[/[0-9]{14}/]
|
41
|
+
test_migration_version = type("ls db/migrate/*_test_migration.rb")[/[0-9]{14}/]
|
42
|
+
db_version.should == test_migration_version
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Then /^the both the staging and test databases should include that migration$/ do
|
47
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
48
|
+
staging_db_version = type("rake db:version RAILS_ENV=staging")[/[0-9]{14}/]
|
49
|
+
test_db_version = type("rake db:version RAILS_ENV=test")[/[0-9]{14}/]
|
50
|
+
test_migration_version = type("ls db/migrate/*_test_migration.rb")[/[0-9]{14}/]
|
51
|
+
staging_db_version.should == test_migration_version
|
52
|
+
test_db_version.should == test_migration_version
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Then /^both the development and test databases should include that migration$/ do
|
57
|
+
Dir.chdir "#{ROOT}/tmp/local" do
|
58
|
+
dev_db_version = type("rake db:version")[/[0-9]{14}/]
|
59
|
+
test_db_version = type("rake db:version RAILS_ENV=test")[/[0-9]{14}/]
|
60
|
+
test_migration_version = type("ls db/migrate/*_test_migration.rb")[/[0-9]{14}/]
|
61
|
+
dev_db_version.should == test_migration_version
|
62
|
+
test_db_version.should == test_migration_version
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Given /^I dont have the test gem installed$/ do
|
67
|
+
type "gem uninstall rake-dotnet -v=0.0.1 -x"
|
68
|
+
end
|
69
|
+
|
70
|
+
Given /^I have committed a set of changes that adds the test gem as a dependency$/ do
|
71
|
+
Dir.chdir "#{ROOT}/tmp/local" do
|
72
|
+
file_inject "config/environment.rb", "
|
73
|
+
Rails::Initializer.run do |config|", <<-RUBY
|
74
|
+
config.gem "rake-dotnet", :version => "0.0.1"
|
75
|
+
RUBY
|
76
|
+
type "git add ."
|
77
|
+
type "git commit -am'added test gem dependency.'"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
Given /^the remote integration branch has had a commit that adds the test gem as a dependency$/ do
|
82
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
83
|
+
file_inject "config/environment.rb", "
|
84
|
+
Rails::Initializer.run do |config|", <<-RUBY
|
85
|
+
config.gem "rake-dotnet", :version => "0.0.1"
|
86
|
+
RUBY
|
87
|
+
type "git add ."
|
88
|
+
type "git commit -am'added test gem dependency.'"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Then /^the test gem should be installed$/ do
|
93
|
+
type("gem list rake-dotnet").should include "rake-dotnet (0.0.1)"
|
94
|
+
end
|
95
|
+
|
96
|
+
Then /^passenger should have been restarted$/ do
|
97
|
+
File.exist?("tmp/restart.txt").should be_true
|
98
|
+
end
|
99
|
+
|
100
|
+
Then /^the staging passenger should have been restarted$/ do
|
101
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
102
|
+
File.exist?("tmp/restart.txt").should be_true
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
Given /^a submodule$/ do
|
2
|
+
Given 'the remote integration branch has had a commit that includes a new submodule'
|
3
|
+
Dir.chdir "#{ROOT}/tmp/local" do
|
4
|
+
type "git checkout integration"
|
5
|
+
type "git pull --rebase"
|
6
|
+
type "git submodule update --init"
|
7
|
+
@submodule_url = File.read(".gitmodules").match(/url = (.*)$/)[1]
|
8
|
+
@submodule_commit = type "git submodule status"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Given /^the submodule working directory is dirty$/ do
|
13
|
+
Dir.chdir "#{ROOT}/tmp/local/submodule" do
|
14
|
+
type "git checkout master"
|
15
|
+
type "echo 'submodule_update' > submodule_update"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Given /^I have committed a set of changes to the submodule$/ do
|
20
|
+
Dir.chdir "#{ROOT}/tmp/local/submodule" do
|
21
|
+
type "git checkout -b master"
|
22
|
+
type "echo 'submodule_update' > submodule_update"
|
23
|
+
type "git add ."
|
24
|
+
type "git commit -am 'update in submodule'"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Given /^the remote integration branch has had a commit that includes a new submodule$/ do
|
29
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
30
|
+
type "git submodule add #{ROOT}/tmp/submodule submodule"
|
31
|
+
Dir.chdir "submodule" do
|
32
|
+
type "git checkout -b master"
|
33
|
+
type "grb track master"
|
34
|
+
end
|
35
|
+
type "git add ."
|
36
|
+
type "git commit -m 'added submodule'"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Given /^I have committed a set of changes that includes a new submodule$/ do
|
41
|
+
type "git submodule add #{ROOT}/tmp/submodule submodule"
|
42
|
+
Dir.chdir "submodule" do
|
43
|
+
type "git checkout -b master"
|
44
|
+
type "grb track master"
|
45
|
+
end
|
46
|
+
type "git add ."
|
47
|
+
type "git commit -m 'added submodule'"
|
48
|
+
end
|
49
|
+
|
50
|
+
Given /^I have committed a set of changes that includes a submodule update$/ do
|
51
|
+
type "git checkout integration"
|
52
|
+
Dir.chdir "submodule" do
|
53
|
+
type "git checkout master"
|
54
|
+
type "echo 'submodule_update' > submodule_update"
|
55
|
+
type "git add ."
|
56
|
+
type "git commit -m 'update in submodule'"
|
57
|
+
type "git push origin HEAD"
|
58
|
+
end
|
59
|
+
type "git add ."
|
60
|
+
type "git commit -m 'updated submodule'"
|
61
|
+
end
|
62
|
+
|
63
|
+
Given /^the remote integration branch has had a commit that includes a submodule update$/ do
|
64
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
65
|
+
Dir.chdir "submodule" do
|
66
|
+
type "git checkout master"
|
67
|
+
type "echo 'submodule_update' > submodule_update"
|
68
|
+
type "git add ."
|
69
|
+
type "git commit -m 'update in submodule'"
|
70
|
+
type "git push origin HEAD"
|
71
|
+
end
|
72
|
+
type "git add ."
|
73
|
+
type "git commit -m 'updated submodule'"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Given /^I have committed a set of changes that includes a submodule url change$/ do
|
78
|
+
gsub_file ".gitmodules", /(url = .*submodule)$/ do |match| "#{match}2" end
|
79
|
+
type "git add ."
|
80
|
+
type "git commit -m 'updated submodule url'"
|
81
|
+
end
|
82
|
+
|
83
|
+
Given /^the remote integration branch has had a commit that includes a submodule url change$/ do
|
84
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
85
|
+
gsub_file ".gitmodules", /(url = .*submodule)$/ do |match| "#{match}2" end
|
86
|
+
type "git add ."
|
87
|
+
type "git commit -m 'updated submodule url'"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Given /^I have committed a set of changes that includes a submodule deletion$/ do
|
92
|
+
type "rm .gitmodules"
|
93
|
+
type "rm -rf --cached submodule"
|
94
|
+
type "git add ."
|
95
|
+
type "git commit -am'removed submodule'"
|
96
|
+
end
|
97
|
+
|
98
|
+
Given /^the remote integration branch has had a commit that includes a submodule deletion$/ do
|
99
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
100
|
+
type "rm .gitmodules"
|
101
|
+
type "rm -rf --cached submodule"
|
102
|
+
type "git add ."
|
103
|
+
type "git commit -am'removed submodule'"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
Then /^there should be one new submodule$/ do
|
108
|
+
status = type "git submodule status"
|
109
|
+
status.should match /.[a-z0-9]{40} submodule/
|
110
|
+
end
|
111
|
+
|
112
|
+
Then /^there should be one new submodule on the remote$/ do
|
113
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
114
|
+
status = type "git submodule status"
|
115
|
+
status.should match /.[a-z0-9]{40} submodule/
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
Then /^the submodule should be checked out$/ do
|
120
|
+
@submodule_url = File.read(".gitmodules").match(/url = (.*)$/)[1]
|
121
|
+
@submodule_commit = type "git submodule status"
|
122
|
+
@submodule_commit.should match %r( [a-z0-9]{40} submodule)
|
123
|
+
end
|
124
|
+
|
125
|
+
Then /^the remote submodule should be checked out$/ do
|
126
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
127
|
+
@submodule_url = File.read(".gitmodules").match(/url = (.*)$/)[1]
|
128
|
+
@submodule_commit = type "git submodule status"
|
129
|
+
@submodule_commit.should match %r( [a-z0-9]{40} submodule)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
Then /^the submodule should be updated$/ do
|
134
|
+
@submodule_commit[/[a-z0-9]{40}/].should_not == type("git submodule status")[/[a-z0-9]{40}/]
|
135
|
+
end
|
136
|
+
|
137
|
+
Then /^the remote submodule should be updated$/ do
|
138
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
139
|
+
@submodule_commit[/[a-z0-9]{40}/].should_not == type("git submodule status")[/[a-z0-9]{40}/]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
Then /^the submodule url should be changed$/ do
|
144
|
+
Dir.chdir "submodule" do
|
145
|
+
remote = type "git remote show origin"
|
146
|
+
remote.should_not match %r(Fetch URL: #{@submodule_url}$)
|
147
|
+
remote.should_not match %r(Push URL: #{@submodule_url}$)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
Then /^the remote submodule url should be changed$/ do
|
152
|
+
Dir.chdir "#{ROOT}/tmp/origin/submodule" do
|
153
|
+
remote = type "git remote show origin"
|
154
|
+
remote.should_not match %r(Fetch URL: #{@submodule_url}$)
|
155
|
+
remote.should_not match %r(Push URL: #{@submodule_url}$)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
Then /^the submodule should be deleted$/ do
|
160
|
+
Then 'the directory should not be dirty'
|
161
|
+
@submodule_commit = type "git submodule status"
|
162
|
+
@submodule_commit.should_not match /.[a-z0-9]{40} submodule/
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
Then /^the remote submodule should be deleted$/ do
|
167
|
+
Then 'the remote directory should not be dirty'
|
168
|
+
Dir.chdir "#{ROOT}/tmp/origin" do
|
169
|
+
@submodule_commit = type "git submodule status"
|
170
|
+
@submodule_commit.should_not match /.[a-z0-9]{40} submodule/
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
|
2
|
+
require 'ruby-debug'
|
3
|
+
require 'grit'
|
4
|
+
require 'spec/expectations'
|
5
|
+
require 'systemu'
|
6
|
+
|
7
|
+
ENV["PATH"] += ":#{File.dirname(File.expand_path(__FILE__))}/../../bin"
|
8
|
+
|
9
|
+
ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Grit::Repo.class_eval do
|
2
|
+
def remote_branches(remote = "origin")
|
3
|
+
branches = self.remotes
|
4
|
+
branches.reject! { |r| r.name !~ %r(^#{remote}/) }
|
5
|
+
branches.collect! { |r| r.name.split('/')[1] }
|
6
|
+
branches.reject! { |b| b == "HEAD" }
|
7
|
+
end
|
8
|
+
|
9
|
+
def submodules
|
10
|
+
Grit::Submodule.config self, self.head.name
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_common_ancestor(head1, head2)
|
14
|
+
`git merge-base #{head1} #{head2}`.chomp
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
def type(command)
|
2
|
+
@status, @stdout, @stderr = systemu command
|
3
|
+
if ENV['DEBUG']
|
4
|
+
puts '-' * 20
|
5
|
+
puts "Executing command: #{command}"
|
6
|
+
puts " Status: #{@status}"
|
7
|
+
puts " Stdout:\n #{@stdout}"
|
8
|
+
puts " Stderr:\n #{@stderr}"
|
9
|
+
puts '-' * 20
|
10
|
+
end
|
11
|
+
@stdout || @stderr
|
12
|
+
end
|
13
|
+
|
14
|
+
def file_inject(file_name, sentinel, string, before_after=:after)
|
15
|
+
gsub_file file_name, /(#{Regexp.escape(sentinel)})/mi do |match|
|
16
|
+
if before_after == :after
|
17
|
+
"#{match}\n#{string}"
|
18
|
+
else
|
19
|
+
"#{string}\n#{match}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def gsub_file(file_name, regexp, *args, &block)
|
25
|
+
content = File.read(file_name).gsub(regexp, *args, &block)
|
26
|
+
File.open(file_name, 'wb') { |file| file.write(content) }
|
27
|
+
end
|
data/lib/bard.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
2
|
+
require 'term/ansicolor'
|
3
|
+
require 'systemu'
|
4
|
+
require 'grit'
|
5
|
+
|
6
|
+
require 'bard/git'
|
7
|
+
require 'bard/io'
|
8
|
+
|
9
|
+
class Bard < Thor
|
10
|
+
include BardGit
|
11
|
+
include BardIO
|
12
|
+
|
13
|
+
desc "pull", "pull changes to your local machine"
|
14
|
+
def pull
|
15
|
+
ensure_integration_branch!
|
16
|
+
ensure_clean_working_directory!
|
17
|
+
|
18
|
+
unless fast_forward_merge?
|
19
|
+
warn "Someone has pushed some changes since you last pulled.\n Please ensure that your changes didnt break stuff."
|
20
|
+
end
|
21
|
+
|
22
|
+
run_crucial "git pull --rebase origin integration"
|
23
|
+
|
24
|
+
changed_files = run_crucial("git diff #{@common_ancestor} origin/integration --diff-filter=ACDMR --name-only").split("\n")
|
25
|
+
puts changed_files.inspect
|
26
|
+
|
27
|
+
if changed_files.any? { |f| f =~ %r(^db/migrate/.+) }
|
28
|
+
run_crucial "rake db:migrate"
|
29
|
+
run_crucial "rake db:migrate RAILS_ENV=test"
|
30
|
+
end
|
31
|
+
|
32
|
+
if changed_files.any? { |f| f == ".gitmodules" }
|
33
|
+
run_crucial "git submodule sync"
|
34
|
+
run_crucial "git submodule init"
|
35
|
+
end
|
36
|
+
run_crucial "git submodule update"
|
37
|
+
|
38
|
+
if changed_files.any? { |f| f =~ %r(^config/environment.+) }
|
39
|
+
run_crucial "rake gems:install"
|
40
|
+
end
|
41
|
+
|
42
|
+
system "touch tmp/restart.txt"
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "push", "push local changes out to the remote"
|
46
|
+
def push
|
47
|
+
ensure_integration_branch!
|
48
|
+
ensure_clean_working_directory!
|
49
|
+
|
50
|
+
if submodule_dirty?
|
51
|
+
fatal "Cannot push changes: You have uncommitted changes to a submodule!\n Please see Micah about this."
|
52
|
+
end
|
53
|
+
|
54
|
+
if submodule_unpushed?
|
55
|
+
fatal "Cannot push changes: You have unpushed changes to a submodule!\n Please see Micah about this."
|
56
|
+
end
|
57
|
+
|
58
|
+
unless fast_forward_merge?
|
59
|
+
fatal "Someone has pushed some changes since you last pulled.\n Kindly run bard pull, ensure that your your changes still work.\n Then run bard push again."
|
60
|
+
end
|
61
|
+
|
62
|
+
run_crucial "git push origin integration", true
|
63
|
+
|
64
|
+
# git post-receive hook runs stage task below
|
65
|
+
end
|
66
|
+
|
67
|
+
if ENV['RAILS_ENV'] == "staging"
|
68
|
+
desc "stage", "!!! INTERNAL USE ONLY !!! reset HEAD to integration, update submodules, run migrations, install gems, restart server"
|
69
|
+
def stage
|
70
|
+
if ENV['GIT_DIR'] == '.'
|
71
|
+
# this means the script has been called as a hook, not manually.
|
72
|
+
# get the proper GIT_DIR so we can descend into the working copy dir;
|
73
|
+
# if we don't then `git reset --hard` doesn't affect the working tree.
|
74
|
+
Dir.chdir '..'
|
75
|
+
ENV['GIT_DIR'] = '.git'
|
76
|
+
end
|
77
|
+
|
78
|
+
run_crucial "git reset --hard"
|
79
|
+
|
80
|
+
# find out the current branch
|
81
|
+
head = File.read('.git/HEAD').chomp
|
82
|
+
# abort if we're on a detached head
|
83
|
+
exit unless head.sub! 'ref: ', ''
|
84
|
+
|
85
|
+
revs = gets.split ' '
|
86
|
+
old_rev, new_rev = revs if head == revs.pop
|
87
|
+
|
88
|
+
changed_files = run_crucial("git diff #{old_rev} #{new_rev} --diff-filter=ACMRD --name-only").split("\n")
|
89
|
+
|
90
|
+
if changed_files.any? { |f| f =~ %r(^db/migrate/.+) }
|
91
|
+
run_crucial "rake db:migrate RAILS_ENV=staging"
|
92
|
+
run_crucial "rake db:migrate RAILS_ENV=test"
|
93
|
+
end
|
94
|
+
|
95
|
+
if changed_files.any? { |f| f == ".gitmodules" }
|
96
|
+
run_crucial "git submodule sync"
|
97
|
+
run_crucial "git submodule init"
|
98
|
+
end
|
99
|
+
system "git submodule update"
|
100
|
+
|
101
|
+
if changed_files.any? { |f| f =~ %r(^config/environment.+) }
|
102
|
+
run_crucial "rake gems:install"
|
103
|
+
end
|
104
|
+
|
105
|
+
system "touch tmp/restart.txt"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/bard/git.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module BardGit
|
2
|
+
private
|
3
|
+
def ensure_integration_branch!
|
4
|
+
return if `git name-rev --name-only HEAD`.chomp == "integration"
|
5
|
+
fatal "You are not on the integration branch! Type `git checkout integration` to switch to it. If you have made changes to your current branch, please see Micah for assistance."
|
6
|
+
end
|
7
|
+
|
8
|
+
def ensure_clean_working_directory!
|
9
|
+
return if`git status`.include? "working directory clean"
|
10
|
+
fatal "Cannot upload changes: You have uncommitted changes!\n Please run git commit before attempting to push or pull."
|
11
|
+
end
|
12
|
+
|
13
|
+
def fast_forward_merge?
|
14
|
+
run_crucial "git fetch origin"
|
15
|
+
head = run_crucial "git rev-parse HEAD"
|
16
|
+
remote_head = run_crucial "git rev-parse origin/integration"
|
17
|
+
@common_ancestor = find_common_ancestor head, remote_head
|
18
|
+
@common_ancestor == remote_head
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_common_ancestor(head1, head2)
|
22
|
+
run_crucial "git merge-base #{head1} #{head2}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def submodule_dirty?
|
26
|
+
@repo ||= Grit::Repo.new "."
|
27
|
+
submodules = Grit::Submodule.config(@repo, @repo.head.name)
|
28
|
+
submodules.any? do |name, submodule|
|
29
|
+
Dir.chdir submodule["path"] do
|
30
|
+
not `git status`.include? "working directory clean"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def submodule_unpushed?
|
36
|
+
@repo ||= Grit::Repo.new "."
|
37
|
+
submodules = Grit::Submodule.config(@repo, @repo.head.name)
|
38
|
+
submodules.any? do |name, submodule|
|
39
|
+
Dir.chdir submodule["path"] do
|
40
|
+
branch = `git name-rev --name-only HEAD`.chomp
|
41
|
+
`git fetch`
|
42
|
+
submodule["id"] != `git rev-parse origin/#{branch}`.chomp
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
data/lib/bard/io.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module BardIO
|
2
|
+
include Term::ANSIColor
|
3
|
+
private
|
4
|
+
|
5
|
+
def warn(message)
|
6
|
+
$stderr.puts yellow("!!! ") + message
|
7
|
+
end
|
8
|
+
|
9
|
+
def fatal(message)
|
10
|
+
raise Thor::Error, red("!!! ") + message
|
11
|
+
end
|
12
|
+
|
13
|
+
def run_crucial(command, verbose = false)
|
14
|
+
status, stdout, stderr = systemu command
|
15
|
+
fatal "Running command: #{yellow(command)}: #{stderr}" if status.to_i.nonzero?
|
16
|
+
if verbose
|
17
|
+
$stdout.puts stdout
|
18
|
+
$stderr.puts stderr
|
19
|
+
end
|
20
|
+
stdout.chomp
|
21
|
+
end
|
22
|
+
end
|
data/spec/bard_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bard
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Micah Geisel
|
8
|
+
- Nick Hogle
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-09-30 00:00:00 -07:00
|
14
|
+
default_executable: bard
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: ruby-debug
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rspec
|
28
|
+
type: :development
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
version:
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: cucumber
|
38
|
+
type: :development
|
39
|
+
version_requirement:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
version:
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rubygems-update
|
48
|
+
type: :runtime
|
49
|
+
version_requirement:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.2
|
55
|
+
version:
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: thor
|
58
|
+
type: :runtime
|
59
|
+
version_requirement:
|
60
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: 0.11.7
|
65
|
+
version:
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: grit
|
68
|
+
type: :runtime
|
69
|
+
version_requirement:
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 1.1.1
|
75
|
+
version:
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: git_remote_branch
|
78
|
+
type: :runtime
|
79
|
+
version_requirement:
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 0.3.0
|
85
|
+
version:
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
name: systemu
|
88
|
+
type: :runtime
|
89
|
+
version_requirement:
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 1.2.0
|
95
|
+
version:
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: term-ansicolor
|
98
|
+
type: :runtime
|
99
|
+
version_requirement:
|
100
|
+
version_requirements: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 1.0.3
|
105
|
+
version:
|
106
|
+
description: This immaculate work of engineering genius allows mere mortals to collaborate with beings of transcendent intelligence like Micah, Michael, and Nick.
|
107
|
+
email: info@botandrose.com
|
108
|
+
executables:
|
109
|
+
- bard
|
110
|
+
extensions: []
|
111
|
+
|
112
|
+
extra_rdoc_files:
|
113
|
+
- LICENSE
|
114
|
+
- README.rdoc
|
115
|
+
files:
|
116
|
+
- .document
|
117
|
+
- .gitignore
|
118
|
+
- .gitmodules
|
119
|
+
- LICENSE
|
120
|
+
- README.rdoc
|
121
|
+
- Rakefile
|
122
|
+
- VERSION
|
123
|
+
- bard.gemspec
|
124
|
+
- bin/bard
|
125
|
+
- features/bard_pull.feature
|
126
|
+
- features/bard_push.feature
|
127
|
+
- features/step_definitions/git_steps.rb
|
128
|
+
- features/step_definitions/global_steps.rb
|
129
|
+
- features/step_definitions/rails_steps.rb
|
130
|
+
- features/step_definitions/submodule_steps.rb
|
131
|
+
- features/support/env.rb
|
132
|
+
- features/support/grit_ext.rb
|
133
|
+
- features/support/io.rb
|
134
|
+
- lib/bard.rb
|
135
|
+
- lib/bard/git.rb
|
136
|
+
- lib/bard/io.rb
|
137
|
+
- spec/bard_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
139
|
+
has_rdoc: true
|
140
|
+
homepage: http://github.com/botandrose/bard
|
141
|
+
licenses: []
|
142
|
+
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options:
|
145
|
+
- --charset=UTF-8
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: "0"
|
153
|
+
version:
|
154
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: "0"
|
159
|
+
version:
|
160
|
+
requirements: []
|
161
|
+
|
162
|
+
rubyforge_project:
|
163
|
+
rubygems_version: 1.3.4
|
164
|
+
signing_key:
|
165
|
+
specification_version: 3
|
166
|
+
summary: Tools for collaborating with Bot and Rose Design.
|
167
|
+
test_files:
|
168
|
+
- spec/spec_helper.rb
|
169
|
+
- spec/bard_spec.rb
|