git_workflow 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/README.markdown +77 -0
  2. data/Rakefile +33 -0
  3. data/bin/git-finish +4 -0
  4. data/bin/git-start +4 -0
  5. data/bin/git-workflow-setup +4 -0
  6. data/features/core_functionality/4049578_need_the_ability_to_start_a_new_branch.feature +15 -0
  7. data/features/core_functionality/4049611_need_the_ability_to_finish_a_specified_branch.feature +17 -0
  8. data/features/core_functionality/4056359_start_with_local_branch_already_present.feature +16 -0
  9. data/features/core_functionality/4056363_finish_the_current_branch.feature +17 -0
  10. data/features/core_functionality/4056389_changes_to_pt_story_name_cause_branch_issues.feature +25 -0
  11. data/features/core_functionality/4135658_control_output_verbosity_using_v_switch.feature +32 -0
  12. data/features/core_functionality/4468313_get_config_value_for_is_producing_an_error_log.feature +43 -0
  13. data/features/extensions/4058326_display_story_description_on_start.feature +14 -0
  14. data/features/git_branching/4135501_allow_branch_start_point_to_be_specified_from_command_line.feature +27 -0
  15. data/features/hooks/4069174_investigate_the_effort_required_to_add_pre_amp_post_hooks.feature +24 -0
  16. data/features/hooks/4199841_need_hooks_for_my_workflow.feature +51 -0
  17. data/features/hooks/4199845_need_hooks_for_sanger_workflow.feature +66 -0
  18. data/features/hooks/4205913_output_from_rake_tests_should_be_seen.feature +19 -0
  19. data/features/hooks/4424828_git_start_is_missing_pt_integration_for_my_hooks.feature +15 -0
  20. data/features/pivotal_tracker_api/4133291_chores_go_straight_to_accepted_not_to_finished.feature +15 -0
  21. data/features/release/4132264_fix_the_libxml_warnings_from_nokogiri.feature +20 -0
  22. data/features/step_definitions/aruba_extensions.rb +4 -0
  23. data/features/step_definitions/configuration_steps.rb +38 -0
  24. data/features/step_definitions/git_steps.rb +102 -0
  25. data/features/step_definitions/misc_steps.rb +3 -0
  26. data/features/step_definitions/pivotal_tracker_steps.rb +43 -0
  27. data/features/step_definitions/project_code_steps.rb +35 -0
  28. data/features/support/aruba.rb +1 -0
  29. data/features/support/hooks/configuration.rb +4 -0
  30. data/features/support/hooks/environment.rb +49 -0
  31. data/features/support/hooks/pivotal_tracker.rb +170 -0
  32. data/lib/git_workflow.rb +5 -0
  33. data/lib/git_workflow/callbacks.rb +16 -0
  34. data/lib/git_workflow/callbacks/pivotal_tracker_support.rb +64 -0
  35. data/lib/git_workflow/callbacks/remote_git_branch_support.rb +9 -0
  36. data/lib/git_workflow/callbacks/styles/debug.rb +58 -0
  37. data/lib/git_workflow/callbacks/styles/default.rb +43 -0
  38. data/lib/git_workflow/callbacks/styles/mine.rb +52 -0
  39. data/lib/git_workflow/callbacks/styles/sanger.rb +48 -0
  40. data/lib/git_workflow/callbacks/test_code_support.rb +29 -0
  41. data/lib/git_workflow/command_line.rb +46 -0
  42. data/lib/git_workflow/commands.rb +4 -0
  43. data/lib/git_workflow/commands/base.rb +31 -0
  44. data/lib/git_workflow/commands/finish.rb +36 -0
  45. data/lib/git_workflow/commands/setup.rb +157 -0
  46. data/lib/git_workflow/commands/start.rb +30 -0
  47. data/lib/git_workflow/configuration.rb +93 -0
  48. data/lib/git_workflow/core_ext.rb +106 -0
  49. data/lib/git_workflow/git.rb +143 -0
  50. data/lib/git_workflow/logger.yaml +27 -0
  51. data/lib/git_workflow/logging.rb +77 -0
  52. data/lib/git_workflow/story.rb +96 -0
  53. data/spec/core_functionality/4056539_support_http_proxy_spec.rb +68 -0
  54. data/spec/core_functionality/4058365_bad_request_on_story_update_spec.rb +13 -0
  55. data/spec/core_functionality/4058394_make_commands_more_verbose_spec.rb +41 -0
  56. data/spec/core_functionality/4058719_error_if_none_of_the_required_configuration_values_are_set_spec.rb +21 -0
  57. data/spec/core_functionality/4058861_git_config_returns_empty_strings_which_should_be_nil_spec.rb +59 -0
  58. data/spec/core_functionality/4172431_add_git_workflow_setup_command_to_make_setup_easier_spec.rb +148 -0
  59. data/spec/core_functionality/4199841_need_callbacks_for_my_workflow_spec.rb +97 -0
  60. data/spec/extensions/4199841_need_callbacks_for_my_workflow_spec.rb +167 -0
  61. data/spec/extensions/4205913_output_from_rake_tests_should_be_seen_spec.rb +34 -0
  62. data/spec/git_branching/4058723_branches_end_in_if_the_last_character_is_invalid_spec.rb +40 -0
  63. data/spec/git_branching/4059824_code_is_not_using_workflow_localbranchconvention_to_decode_branch_names_on_finish_spec.rb +115 -0
  64. data/spec/git_branching/4216087_support_pushing_branches_spec.rb +44 -0
  65. data/spec/hooks/4199845_need_hooks_for_sanger_workflow_spec.rb +27 -0
  66. data/spec/pivotal_tracker_api/4056381_pt_api_token_not_being_passed_in_headers_spec.rb +40 -0
  67. data/spec/pivotal_tracker_api/4056638_library_code_using_localhost_spec.rb +16 -0
  68. data/spec/pivotal_tracker_api/4056661_content_type_header_should_be_text_xml_on_updates_spec.rb +16 -0
  69. data/spec/pivotal_tracker_api/4058718_if_pt_username_is_not_set_use_user_name_spec.rb +26 -0
  70. data/spec/pivotal_tracker_api/4146016_decode_the_xml_encoded_text_of_description_and_name_spec.rb +63 -0
  71. data/spec/shared_examples/configuration.rb +10 -0
  72. data/spec/shared_examples/story.rb +17 -0
  73. data/spec/spec_helper.rb +18 -0
  74. metadata +220 -0
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitWorkflow::Git do
4
+ before(:each) do
5
+ @git, @repository = Class.new, mock('Repository')
6
+ @git.send(:extend, GitWorkflow::Git)
7
+ @git.stub(:repository).and_return(@repository)
8
+
9
+ @git.stub(:info).with(anything)
10
+ end
11
+
12
+ describe '#in_git_branch' do
13
+ before(:each) do
14
+ @repository.should_receive(:current_branch).ordered.and_return('current')
15
+ end
16
+
17
+ it 'does not switch back if an error occurs' do
18
+ @repository.should_receive(:checkout).with('new_branch').ordered
19
+
20
+ lambda do
21
+ @git.in_git_branch('new_branch') { raise StandardError, 'Failed' }
22
+ end.should raise_error(StandardError)
23
+ end
24
+
25
+ context 'with a successful block' do
26
+ before(:each) do
27
+ @callback = mock('callback')
28
+ @callback.should_receive(:called)
29
+ end
30
+
31
+ after(:each) do
32
+ @git.in_git_branch(@target_branch) { @callback.called }
33
+ end
34
+
35
+ it 'simply yields if the current branch is the requested branch' do
36
+ @target_branch = 'current'
37
+ end
38
+
39
+ it 'switches to the new branch and back again for success' do
40
+ @target_branch = 'new_branch'
41
+
42
+ @repository.should_receive(:checkout).with('new_branch').ordered
43
+ @repository.should_receive(:checkout).with('current').ordered
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ class GitWorkflow::Git::Repository
50
+ def self.for_testing
51
+ new
52
+ end
53
+
54
+ def internal_current_branch
55
+ @current_branch
56
+ end
57
+ end
58
+
59
+ describe GitWorkflow::Git::Repository do
60
+ before(:each) do
61
+ @repository = described_class.for_testing
62
+ end
63
+
64
+ describe '#current_branch' do
65
+ it 'finds the current branch from the list' do
66
+ @repository.should_receive(:execute_command).with('git branch').and_return([ ' branch_1', '* branch_2', ' branch_3' ].join("\n"))
67
+ @repository.current_branch.should == 'branch_2'
68
+ end
69
+
70
+ it 'raises if the current branch cannot be found in the list' do
71
+ @repository.should_receive(:execute_command).with('git branch').and_return([ ' branch_1', ' branch_2', ' branch_3' ].join("\n"))
72
+ lambda { @repository.current_branch }.should raise_error(GitWorkflow::Git::Repository::BranchError)
73
+ end
74
+ end
75
+
76
+ describe '#checkout' do
77
+ it 'raises CheckoutError on command failure' do
78
+ @repository.should_receive(:execute_command).with(anything).and_raise(Execution::CommandFailure.new('command', :fail))
79
+ lambda { @repository.checkout('target') }.should raise_error(GitWorkflow::Git::Repository::CheckoutError)
80
+ end
81
+
82
+ context 'on successful checkout' do
83
+ before(:each) do
84
+ @repository.should_receive(:execute_command).with('git checkout target')
85
+ @repository.checkout('target')
86
+ end
87
+
88
+ it 'checks out the requested branch' do
89
+ # Nothing needed here
90
+ end
91
+
92
+ it 'maintains the current branch for performance' do
93
+ @repository.internal_current_branch.should == 'target'
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+ require 'git_workflow/callbacks/styles/mine'
3
+
4
+ describe String do
5
+ describe '#camelize' do
6
+ it 'camelizes an underscored word' do
7
+ 'foo_bar_baz'.camelize.should == 'FooBarBaz'
8
+ end
9
+
10
+ it 'modularizes a path' do
11
+ 'foo/bar/baz'.camelize.should == 'Foo::Bar::Baz'
12
+ end
13
+ end
14
+
15
+ describe '#underscore' do
16
+ it 'underscores a modular string' do
17
+ 'Foo::Bar::Baz'.underscore.should == 'foo/bar/baz'
18
+ end
19
+
20
+ it 'underscores a camelized word' do
21
+ 'FooBarBaz'.underscore.should == 'foo_bar_baz'
22
+ end
23
+ end
24
+ end
25
+
26
+ describe GitWorkflow::Callbacks::Styles::Mine::FinishBehaviour do
27
+ before(:each) do
28
+ @callbacks = Class.new
29
+ @callbacks.send(:extend, GitWorkflow::Callbacks::Styles::Mine::FinishBehaviour)
30
+ end
31
+
32
+ describe '#finish' do
33
+ before(:each) do
34
+ @story = mock('Story')
35
+ @story.stub(:branch_name).and_return('story_branch')
36
+
37
+ @callbacks.should_receive(:in_git_branch).with('story_branch').and_yield.ordered
38
+ @callbacks.should_receive(:run_tests!).with(:spec, :features).ordered
39
+ end
40
+
41
+ after(:each) do
42
+ @callbacks.finish(@story, @target_branch)
43
+ end
44
+
45
+ it 'runs the tests but not the push if non-master branch' do
46
+ @target_branch = 'non-master'
47
+
48
+ @callbacks.should_receive(:in_git_branch).with(@target_branch).and_yield.ordered
49
+ @callbacks.should_receive(:merge_branch).with('story_branch', anything).ordered
50
+ @callbacks.should_receive(:run_tests_with_recovery!).with(:spec, :features).ordered
51
+
52
+ @callbacks.should_not_receive(:push_current_branch_to).with('non-master').ordered
53
+ end
54
+
55
+ it 'runs the tests and the push if master branch' do
56
+ @target_branch = 'master'
57
+
58
+ @callbacks.should_receive(:in_git_branch).with(@target_branch).and_yield.ordered
59
+ @callbacks.should_receive(:merge_branch).with('story_branch', anything).ordered
60
+ @callbacks.should_receive(:run_tests_with_recovery!).with(:spec, :features).ordered
61
+
62
+ @callbacks.should_receive(:push_current_branch_to).with('master').ordered
63
+ end
64
+ end
65
+ end
66
+
67
+ describe GitWorkflow::Callbacks::Styles::Mine do
68
+ describe '.setup' do
69
+ before(:each) do
70
+ @start, @finish = Class.new, Class.new
71
+
72
+ GitWorkflow::Callbacks::Styles::Mine.setup(@start, @finish)
73
+ end
74
+
75
+ context 'configured start' do
76
+ it 'has my callbacks installed' do
77
+ @start.included_modules.should include(GitWorkflow::Callbacks::Styles::Mine::StartBehaviour)
78
+ end
79
+ end
80
+
81
+ context 'configured finish' do
82
+ it 'has the Pivotal Tracker support' do
83
+ @finish.included_modules.should include(GitWorkflow::Callbacks::PivotalTrackerSupport)
84
+ end
85
+
86
+ it 'has the test code support' do
87
+ @finish.included_modules.should include(GitWorkflow::Callbacks::TestCodeSupport)
88
+ end
89
+
90
+ it 'has the remote git branch support' do
91
+ @finish.included_modules.should include(GitWorkflow::Callbacks::RemoteGitBranchSupport)
92
+ end
93
+
94
+ it 'has my callbacks installed' do
95
+ @finish.included_modules.should include(GitWorkflow::Callbacks::Styles::Mine::FinishBehaviour)
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ describe GitWorkflow::Callbacks::TestCodeSupport do
102
+ before(:each) do
103
+ @callbacks = Class.new
104
+ @callbacks.send(:extend, GitWorkflow::Callbacks::TestCodeSupport)
105
+ end
106
+
107
+ describe '#run_tests!' do
108
+ it 'does nothing if the tests pass' do
109
+ @callbacks.should_receive(:run_tests).with(:task1, :task2).once.and_return(true)
110
+
111
+ @callbacks.run_tests!(:task1, :task2)
112
+ end
113
+
114
+ it 'raises if the tests fail' do
115
+ @callbacks.should_receive(:run_tests).with(:task1, :task2).once.and_return(false)
116
+
117
+ lambda { @callbacks.run_tests!(:task1, :task2) }.should raise_error(GitWorkflow::Callbacks::TestCodeSupport::Failure)
118
+ end
119
+ end
120
+
121
+ describe '#run_tests_with_recovery!' do
122
+ it 'does nothing if the tests pass' do
123
+ @callbacks.should_receive(:run_tests).with(:task1, :task2).once.and_return(true)
124
+
125
+ @callbacks.run_tests_with_recovery!(:task1, :task2)
126
+ end
127
+
128
+ it 'tries to recover from failing tests' do
129
+ @callbacks.should_receive(:run_tests).with(:task1, :task2).twice.and_return(false, true)
130
+ @callbacks.should_receive(:spawn_shell_for_recovery).once.and_return(true)
131
+
132
+ @callbacks.run_tests_with_recovery!(:task1, :task2)
133
+ end
134
+
135
+ it 'raises if the recovery is not possible' do
136
+ @callbacks.should_receive(:run_tests).with(:task1, :task2).once.and_return(false)
137
+ @callbacks.should_receive(:spawn_shell_for_recovery).once.and_return(false)
138
+
139
+ lambda { @callbacks.run_tests_with_recovery!(:task1, :task2) }.should raise_error(GitWorkflow::Callbacks::TestCodeSupport::Failure)
140
+ end
141
+ end
142
+
143
+ describe '#run_tests' do
144
+ it 'executes the given rake tasks' do
145
+ @callbacks.should_receive(:system).with('rake', 'task1', 'task2').and_return(true)
146
+ @callbacks.send(:run_tests, :task1, :task2).should == true
147
+ end
148
+
149
+ it 'returns the result of execution' do
150
+ @callbacks.should_receive(:system).with('rake', 'task1', 'task2').and_return(false)
151
+ @callbacks.send(:run_tests, :task1, :task2).should == false
152
+ end
153
+ end
154
+
155
+ describe '#spawn_shell_for_recovery' do
156
+ end
157
+ end
158
+
159
+ describe GitWorkflow::Callbacks::RemoteGitBranchSupport do
160
+ before(:each) do
161
+ @callbacks = Class.new
162
+ @callbacks.send(:extend, GitWorkflow::Callbacks::RemoteGitBranchSupport)
163
+ end
164
+
165
+ describe '#push_current_branch_to' do
166
+ end
167
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Execution do
4
+ before(:each) do
5
+ @executor = Class.new
6
+ @executor.send(:extend, Execution)
7
+ @executor.stub(:debug).with(anything).and_yield
8
+ end
9
+
10
+ before(:each) do
11
+ @stdin, @stdout, @stderr = mock('stdin'), mock('stdout'), mock('stderr')
12
+ @outputs = [ @stdout, @stderr, @stdin ]
13
+ end
14
+
15
+ describe '#execute_command' do
16
+ it 'returns the output from the command' do
17
+ @stdout.should_receive(:read).and_return('Hello World')
18
+ @executor.should_receive(:execute_command_with_output_handling).with(:command).and_yield(*@outputs)
19
+ @executor.execute_command(:command).should == 'Hello World'
20
+ end
21
+ end
22
+
23
+ describe '#execute_command_with_output_handling' do
24
+ it 'does not raise if the command succeeds' do
25
+ @executor.execute_command_with_output_handling('sh -c "exit 0"') { |*args| }
26
+ end
27
+
28
+ it 'raises if the command fails' do
29
+ lambda do
30
+ @executor.execute_command_with_output_handling('sh -c "exit 1"') { |*args| }
31
+ end.should raise_error(Execution::CommandFailure)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ class GitWorkflow::Story
4
+ attr_writer :name
5
+ end
6
+
7
+ describe GitWorkflow::Story do
8
+ describe '#branch_name' do
9
+ it_should_behave_like 'it needs a working Story'
10
+
11
+ it 'delegates to the local branch convention' do
12
+ configuration, convention = mock('configuration'), mock('convention')
13
+ configuration.should_receive(:local_branch_convention).and_return(convention)
14
+ convention.should_receive(:to).with(@story).and_return(:ok)
15
+ GitWorkflow::Configuration.stub!(:instance).and_return(configuration)
16
+
17
+ @story.branch_name.should == :ok
18
+ end
19
+ end
20
+ end
21
+
22
+ describe GitWorkflow::Configuration::Convention do
23
+ describe '#to' do
24
+ before(:each) do
25
+ @convention = described_class.new('${number}_${name}')
26
+ end
27
+
28
+ after(:each) do
29
+ @convention.to(OpenStruct.new(:story_id => 12345, :name => @name)).should_not match(/_+$/)
30
+ end
31
+
32
+ it 'does not end in underscore with invalid character at the end' do
33
+ @name = 'ends in invalid character!'
34
+ end
35
+
36
+ it 'does not end in multiple underscores' do
37
+ @name = 'ends in invalid characters!!!!!!!'
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+
3
+ class GitWorkflow::Configuration
4
+ def self.instance_for_testing
5
+ new
6
+ end
7
+ end
8
+
9
+ describe GitWorkflow::Configuration do
10
+ describe '#local_branch_convention' do
11
+ before(:each) do
12
+ @configuration = GitWorkflow::Configuration.instance_for_testing
13
+ @configuration.should_receive(:get_config_value_for!).with('workflow.localbranchconvention').once.and_return('${number}_${name}')
14
+ end
15
+
16
+ it 'uses the workflow.localbranchconvention configuration value' do
17
+ @configuration.local_branch_convention
18
+ end
19
+
20
+ it 'caches the value' do
21
+ @configuration.local_branch_convention # Gets the value ...
22
+ @configuration.local_branch_convention # ... that should now be cached
23
+ end
24
+ end
25
+ end
26
+
27
+ class GitWorkflow::Commands::Finish
28
+ public :extract_story_from_branch
29
+ end
30
+
31
+ describe GitWorkflow::Commands::Finish do
32
+ before(:each) do
33
+ @configuration = mock('configuration')
34
+ @configuration.stub(:ignore_git_global?).and_return(false)
35
+ GitWorkflow::Configuration.stub!(:instance).and_return(@configuration)
36
+
37
+ @command = described_class.new([])
38
+ end
39
+
40
+ describe '#extract_story_from_branch' do
41
+ before(:each) do
42
+ @convention = mock('convention')
43
+ @configuration.stub!(:local_branch_convention).and_return(@convention)
44
+ end
45
+
46
+ it 'uses the branch convention' do
47
+ @convention.should_receive(:from).with('12345_this_branch_matches').and_return(12345)
48
+ @command.extract_story_from_branch('12345_this_branch_matches').should == 12345
49
+ end
50
+ end
51
+ end
52
+
53
+ describe GitWorkflow::Configuration::Convention do
54
+ describe '#initialize' do
55
+ it 'errors if the convention has no story_id' do
56
+ lambda { described_class.new('foo') }.should raise_error(StandardError)
57
+ end
58
+
59
+ it 'does not error if story_id included' do
60
+ described_class.new('${number}_foo')
61
+ end
62
+ end
63
+
64
+ shared_examples_for 'branch convention behaviour' do
65
+ before(:each) do
66
+ @branches = { :start => '12345_works_for_me', :end => 'works_for_me_12345' }
67
+ end
68
+
69
+ describe '#to' do
70
+ before(:each) do
71
+ @decoder = described_class.new(@convention)
72
+ @decoder.stub!(:use_existing_for).with(anything).and_return(nil)
73
+ end
74
+
75
+ it 'evaluates the convention string' do
76
+ story = OpenStruct.new(:story_id => 12345, :name => 'works for me')
77
+ @decoder.to(story).should == @branches[ @to_result ]
78
+ end
79
+ end
80
+
81
+ describe '#from' do
82
+ before(:each) do
83
+ @decoder = described_class.new(@convention)
84
+ end
85
+
86
+ it 'decodes the same branch that #to produces' do
87
+ @decoder.from(@branches[ @to_result ]).should == 12345
88
+ end
89
+
90
+ it 'errors if the branch does not conform to the convention' do
91
+ lambda { @decoder.from(@branches[ @from_mismatch ]) }.should raise_error(StandardError)
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'after successful initialization' do
97
+ context 'with ${number}_${name}' do
98
+ it_should_behave_like 'branch convention behaviour'
99
+
100
+ before(:each) do
101
+ @convention = '${number}_${name}'
102
+ @to_result, @from_mismatch = :start, :end
103
+ end
104
+ end
105
+
106
+ context 'with ${name}_${number}' do
107
+ it_should_behave_like 'branch convention behaviour'
108
+
109
+ before(:each) do
110
+ @convention = '${name}_${number}'
111
+ @to_result, @from_mismatch = :end, :start
112
+ end
113
+ end
114
+ end
115
+ end