git-process-lib 2.0.0

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 (69) hide show
  1. data/CHANGELOG.md +123 -0
  2. data/Gemfile +21 -0
  3. data/Gemfile.lock +57 -0
  4. data/LICENSE +193 -0
  5. data/README.md +342 -0
  6. data/Rakefile +32 -0
  7. data/bin/git-new-fb +39 -0
  8. data/bin/git-pull-request +63 -0
  9. data/bin/git-sync +38 -0
  10. data/bin/git-to-master +44 -0
  11. data/docs/git-new-fb.1.adoc +83 -0
  12. data/docs/git-process.1.adoc +227 -0
  13. data/docs/git-pull-request.1.adoc +166 -0
  14. data/docs/git-sync.1.adoc +120 -0
  15. data/docs/git-to-master.1.adoc +172 -0
  16. data/git-new-fb.gemspec +20 -0
  17. data/git-process-lib.gemspec +25 -0
  18. data/git-process.gemspec +22 -0
  19. data/git-pull-request.gemspec +20 -0
  20. data/git-sync.gemspec +20 -0
  21. data/git-to-master.gemspec +20 -0
  22. data/lib/git-process/abstract_error_builder.rb +53 -0
  23. data/lib/git-process/changed_file_helper.rb +115 -0
  24. data/lib/git-process/git_abstract_merge_error_builder.rb +130 -0
  25. data/lib/git-process/git_branch.rb +105 -0
  26. data/lib/git-process/git_branches.rb +81 -0
  27. data/lib/git-process/git_config.rb +135 -0
  28. data/lib/git-process/git_lib.rb +646 -0
  29. data/lib/git-process/git_logger.rb +84 -0
  30. data/lib/git-process/git_merge_error.rb +28 -0
  31. data/lib/git-process/git_process.rb +159 -0
  32. data/lib/git-process/git_process_error.rb +18 -0
  33. data/lib/git-process/git_process_options.rb +101 -0
  34. data/lib/git-process/git_rebase_error.rb +30 -0
  35. data/lib/git-process/git_remote.rb +222 -0
  36. data/lib/git-process/git_status.rb +108 -0
  37. data/lib/git-process/github_configuration.rb +298 -0
  38. data/lib/git-process/github_pull_request.rb +165 -0
  39. data/lib/git-process/new_fb.rb +49 -0
  40. data/lib/git-process/parked_changes_error.rb +41 -0
  41. data/lib/git-process/pull_request.rb +136 -0
  42. data/lib/git-process/pull_request_error.rb +25 -0
  43. data/lib/git-process/rebase_to_master.rb +148 -0
  44. data/lib/git-process/sync_process.rb +55 -0
  45. data/lib/git-process/syncer.rb +157 -0
  46. data/lib/git-process/uncommitted_changes_error.rb +23 -0
  47. data/lib/git-process/version.rb +22 -0
  48. data/local-build.rb +24 -0
  49. data/spec/FileHelpers.rb +19 -0
  50. data/spec/GitRepoHelper.rb +123 -0
  51. data/spec/changed_file_helper_spec.rb +127 -0
  52. data/spec/git_abstract_merge_error_builder_spec.rb +64 -0
  53. data/spec/git_branch_spec.rb +123 -0
  54. data/spec/git_config_spec.rb +45 -0
  55. data/spec/git_lib_spec.rb +176 -0
  56. data/spec/git_logger_spec.rb +66 -0
  57. data/spec/git_process_spec.rb +208 -0
  58. data/spec/git_remote_spec.rb +227 -0
  59. data/spec/git_status_spec.rb +122 -0
  60. data/spec/github_configuration_spec.rb +152 -0
  61. data/spec/github_pull_request_spec.rb +117 -0
  62. data/spec/github_test_helper.rb +49 -0
  63. data/spec/new_fb_spec.rb +126 -0
  64. data/spec/pull_request_helper.rb +94 -0
  65. data/spec/pull_request_spec.rb +137 -0
  66. data/spec/rebase_to_master_spec.rb +362 -0
  67. data/spec/spec_helper.rb +21 -0
  68. data/spec/sync_spec.rb +1474 -0
  69. metadata +249 -0
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../lib/git-process/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Jim Moore"]
5
+ gem.email = %w(moore.jim@gmail.com)
6
+ gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
+ gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
+ gem.homepage = "http://jdigger.github.com/git-process/"
9
+ gem.license = 'ASL2'
10
+
11
+ gem.add_dependency "git-process-lib", GitProc::Version::STRING
12
+
13
+ gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-new-fb)
14
+ gem.files << 'man/git-new-fb.1'
15
+ gem.executables = ['git-new-fb']
16
+ gem.name = "git-new-fb"
17
+ gem.version = GitProc::Version::STRING
18
+ gem.platform = Gem::Platform::RUBY
19
+ gem.required_ruby_version = '>= 1.8.7'
20
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path('../lib/git-process/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Jim Moore"]
5
+ gem.email = %w(moore.jim@gmail.com)
6
+ gem.description = %q{The libraries for the git-process suite of tools}
7
+ gem.summary = %q{The libraries for the git-process suite of tools}
8
+ gem.homepage = "http://jdigger.github.com/git-process/"
9
+ gem.license = 'ASL2'
10
+
11
+ gem.add_dependency "octokit", "~> 1.24" # GitHub API
12
+ gem.add_dependency "json", "~> 1.7.3"
13
+ gem.add_dependency "trollop", "~> 1.16.2" # CLI options parser
14
+ gem.add_dependency "highline", "1.6.13" # user CLI interaction. There is a bug in 1.6.14
15
+ gem.add_dependency "addressable", "~> 2.3.4" # URI processing
16
+ gem.add_dependency "gem-man", "~> 0.3" # man page support for Gems
17
+
18
+ gem.files = `git ls-files`.split($\).delete_if { |f| f =~ /^\./ }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.name = "git-process-lib"
21
+ gem.require_paths = %w(lib)
22
+ gem.version = GitProc::Version::STRING
23
+ gem.platform = Gem::Platform::RUBY
24
+ gem.required_ruby_version = '>= 1.8.7'
25
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../lib/git-process/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Jim Moore"]
5
+ gem.email = %w(moore.jim@gmail.com)
6
+ gem.description = %q{A set of scripts to make working with git easier and more consistent}
7
+ gem.summary = %q{A set of scripts for a good git process}
8
+ gem.homepage = "http://jdigger.github.com/git-process/"
9
+ gem.license = 'ASL2'
10
+
11
+ gem.add_dependency "git-sync", GitProc::Version::STRING
12
+ gem.add_dependency "git-new-fb", GitProc::Version::STRING
13
+ gem.add_dependency "git-to-master", GitProc::Version::STRING
14
+ gem.add_dependency "git-pull-request", GitProc::Version::STRING
15
+
16
+ gem.files = %w(README.md LICENSE CHANGELOG.md)
17
+ gem.files << 'man/git-process.1'
18
+ gem.name = "git-process"
19
+ gem.version = GitProc::Version::STRING
20
+ gem.platform = Gem::Platform::RUBY
21
+ gem.required_ruby_version = '>= 1.8.7'
22
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../lib/git-process/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Jim Moore"]
5
+ gem.email = %w(moore.jim@gmail.com)
6
+ gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
+ gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
+ gem.homepage = "http://jdigger.github.com/git-process/"
9
+ gem.license = 'ASL2'
10
+
11
+ gem.add_dependency "git-process-lib", GitProc::Version::STRING
12
+
13
+ gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-pull-request)
14
+ gem.files << 'man/git-pull-request.1'
15
+ gem.executables = ['git-pull-request']
16
+ gem.name = "git-pull-request"
17
+ gem.version = GitProc::Version::STRING
18
+ gem.platform = Gem::Platform::RUBY
19
+ gem.required_ruby_version = '>= 1.8.7'
20
+ end
data/git-sync.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../lib/git-process/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Jim Moore"]
5
+ gem.email = %w(moore.jim@gmail.com)
6
+ gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
+ gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
+ gem.homepage = "http://jdigger.github.com/git-process/"
9
+ gem.license = 'ASL2'
10
+
11
+ gem.add_dependency "git-process-lib", GitProc::Version::STRING
12
+
13
+ gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-sync)
14
+ gem.files << 'man/git-sync.1'
15
+ gem.executables = ['git-sync']
16
+ gem.name = "git-sync"
17
+ gem.version = GitProc::Version::STRING
18
+ gem.platform = Gem::Platform::RUBY
19
+ gem.required_ruby_version = '>= 1.8.7'
20
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../lib/git-process/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Jim Moore"]
5
+ gem.email = %w(moore.jim@gmail.com)
6
+ gem.description = %q{Fetches the latest repository from the server, rebases/merges the current branch against the changes in the integration branch, then pushes the result up to a branch on the server of the same name. (Unless told not to.)}
7
+ gem.summary = %q{Gets the latest changes that have happened on the integration branch, then pushes your changes to a feature branch on the server.}
8
+ gem.homepage = "http://jdigger.github.com/git-process/"
9
+ gem.license = 'ASL2'
10
+
11
+ gem.add_dependency "git-process-lib", GitProc::Version::STRING
12
+
13
+ gem.files = %w(README.md LICENSE CHANGELOG.md bin/git-to-master)
14
+ gem.files << 'man/git-to-master.1'
15
+ gem.executables = ['git-to-master']
16
+ gem.name = "git-to-master"
17
+ gem.version = GitProc::Version::STRING
18
+ gem.platform = Gem::Platform::RUBY
19
+ gem.required_ruby_version = '>= 1.8.7'
20
+ end
@@ -0,0 +1,53 @@
1
+ # Licensed under the Apache License, Version 2.0 (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'shellwords'
14
+
15
+ module GitProc
16
+
17
+ module AbstractErrorBuilder
18
+
19
+ def commands
20
+ @commands ||= build_commands
21
+ end
22
+
23
+
24
+ def build_message
25
+ msg = human_message
26
+
27
+ msg << append_commands
28
+ end
29
+
30
+
31
+ def append_commands
32
+ commands.empty? ? '' : "\n\nCommands:\n\n #{commands.join("\n ")}"
33
+ end
34
+
35
+
36
+ def human_message
37
+ ''
38
+ end
39
+
40
+
41
+ def build_commands
42
+ []
43
+ end
44
+
45
+
46
+ def shell_escaped_files(files)
47
+ shell_escaped_files = files.map { |f| f.shellescape }
48
+ shell_escaped_files.join(' ')
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,115 @@
1
+ # Licensed under the Apache License, Version 2.0 (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'git-process/git_lib'
14
+ require 'highline/import'
15
+
16
+
17
+ module GitProc
18
+
19
+ #
20
+ # Provides support for prompting the user when the dir/index is dirty.
21
+ #
22
+ #noinspection RubyControlFlowConversionInspection,RubyClassMethodNamingConvention,RubyInstanceMethodNamingConvention
23
+ class ChangeFileHelper
24
+
25
+ # @param [GitLib] gitlib
26
+ def initialize(gitlib)
27
+ @gitlib = gitlib
28
+ end
29
+
30
+
31
+ def offer_to_help_uncommitted_changes
32
+ stat = gitlib.status
33
+
34
+ if stat.unmerged.empty?
35
+ handle_unknown_files(stat)
36
+ handle_changed_files(gitlib.status) # refresh status in case it changed earlier
37
+ else
38
+ gitlib.logger.info { "Can not offer to auto-add unmerged files: #{stat.unmerged.inspect}" }
39
+ raise UncommittedChangesError.new
40
+ end
41
+ end
42
+
43
+
44
+ #noinspection RubyControlFlowConversionInspection
45
+ def handle_unknown_files(stat)
46
+ if not stat.unknown.empty?
47
+ resp = ChangeFileHelper.ask_how_to_handle_unknown_files(stat)
48
+ if resp == :add
49
+ gitlib.add(stat.unknown)
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ def handle_changed_files(stat)
56
+ if not stat.modified.empty? or not stat.added.empty? or not stat.deleted.empty?
57
+ resp = ChangeFileHelper.ask_how_to_handle_changed_files(stat)
58
+ if resp == :commit
59
+ changed_files = (stat.added + stat.modified - stat.deleted).sort.uniq
60
+
61
+ gitlib.add(changed_files) unless changed_files.empty?
62
+ gitlib.remove(stat.deleted) unless stat.deleted.empty?
63
+
64
+ gitlib.commit(nil)
65
+ else
66
+ gitlib.stash_save
67
+ end
68
+ end
69
+ end
70
+
71
+
72
+ def self.ask_how_to_handle_unknown_files(stat)
73
+ show_changes(:unknown, stat)
74
+ resp = ask('Would you like to (a)dd them or (i)gnore them? ') do |q|
75
+ q.responses[:not_valid] = 'Please respond with either (a)dd or (i)gnore. (Ctl-C to abort.) '
76
+ q.case = :down
77
+ q.validate = /a|i/i
78
+ end
79
+
80
+ resp == 'a' ? :add : :ignore
81
+ end
82
+
83
+
84
+ def self.show_changes(type, stat)
85
+ files = stat.send(type)
86
+
87
+ if type != :deleted
88
+ files -= stat.deleted
89
+ end
90
+
91
+ if not files.empty?
92
+ say("You have <%= color('#{type}', [:underline]) %> files:\n <%= color('#{files.join("\n ")}', [:bold]) %>")
93
+ end
94
+ end
95
+
96
+
97
+ def self.ask_how_to_handle_changed_files(stat)
98
+ [:added, :modified, :deleted].each { |t| show_changes(t, stat) }
99
+ resp = ask('Would you like to (c)ommit them or (s)tash them? ') do |q|
100
+ q.responses[:not_valid] = 'Please respond with either (c)ommit or (s)tash. (Ctl-C to abort.) '
101
+ q.case = :down
102
+ q.validate = /c|s/i
103
+ end
104
+
105
+ resp == 'c' ? :commit : :stash
106
+ end
107
+
108
+
109
+ def gitlib
110
+ @gitlib
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,130 @@
1
+ # Licensed under the Apache License, Version 2.0 (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'git-process/abstract_error_builder'
14
+ require 'shellwords'
15
+
16
+ module GitProc
17
+
18
+ #noinspection RubyTooManyInstanceVariablesInspection
19
+ class AbstractMergeErrorBuilder
20
+ include GitProc::AbstractErrorBuilder
21
+
22
+ attr_reader :gitlib, :error_message, :continue_command
23
+
24
+
25
+ def initialize(gitlib, error_message, continue_command)
26
+ @gitlib = gitlib
27
+ @error_message = error_message
28
+ @continue_command = continue_command
29
+ end
30
+
31
+
32
+ def resolved_files
33
+ @resolved_files ||= find_resolved_files
34
+ end
35
+
36
+
37
+ def unresolved_files
38
+ @unresolved_files ||= (unmerged - resolved_files)
39
+ end
40
+
41
+
42
+ def find_resolved_files
43
+ resolved_files = []
44
+
45
+ unmerged.each do |file|
46
+ resolved_file = (/Resolved '#{file}' using previous resolution./m =~ error_message)
47
+ resolved_files << file if resolved_file
48
+ end
49
+
50
+ resolved_files.sort
51
+ end
52
+
53
+
54
+ def human_message
55
+ msg = 'There was a problem merging.'
56
+
57
+ unresolved_files.each do |file|
58
+ if modified.include? file
59
+ msg << "\n'#{file}' was modified in both branches."
60
+ end
61
+ end
62
+
63
+ msg
64
+ end
65
+
66
+
67
+ def build_commands
68
+ commands = []
69
+
70
+ unless resolved_files.empty?
71
+ escaped_files = shell_escaped_files(resolved_files)
72
+ commands << "git add #{escaped_files}"
73
+ end
74
+
75
+ unless unresolved_files.empty?
76
+ mergeable = unresolved_files & modified
77
+ commands << "git mergetool #{shell_escaped_files(mergeable)}" unless mergeable.empty?
78
+ mergeable.each do |f|
79
+ commands << "# Verify '#{f}' merged correctly."
80
+ end
81
+ (unresolved_files & added).each do |f|
82
+ commands << "# '#{f}' was added in both branches; Fix the conflict."
83
+ end
84
+ commands << "git add #{shell_escaped_files(unresolved_files)}"
85
+ end
86
+
87
+ commands << continue_command if continue_command
88
+
89
+ commands
90
+ end
91
+
92
+
93
+ attr_writer :unmerged, :added, :deleted, :modified
94
+
95
+
96
+ def unmerged
97
+ @unmerged ||= status.unmerged
98
+ end
99
+
100
+
101
+ def added
102
+ @added ||= status.added
103
+ end
104
+
105
+
106
+ def deleted
107
+ @deleted ||= status.deleted
108
+ end
109
+
110
+
111
+ def modified
112
+ @modified ||= status.modified
113
+ end
114
+
115
+
116
+ private
117
+
118
+
119
+ def config
120
+ gitlib.config
121
+ end
122
+
123
+
124
+ def status
125
+ @status ||= gitlib.status
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,105 @@
1
+ # Licensed under the Apache License, Version 2.0 (the "License");
2
+ # you may not use this file except in compliance with the License.
3
+ # You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module GitProc
14
+
15
+ class GitBranch
16
+ include Comparable
17
+
18
+ attr_reader :name
19
+
20
+
21
+ def initialize(name, current, lib)
22
+ if /^remotes\// =~ name
23
+ @name = name[8..-1]
24
+ @remote = true
25
+ else
26
+ @name = name
27
+ @remote = false
28
+ end
29
+ @current = current
30
+ @lib = lib
31
+ end
32
+
33
+
34
+ def current?
35
+ @current
36
+ end
37
+
38
+
39
+ def remote?
40
+ @remote
41
+ end
42
+
43
+
44
+ def local?
45
+ !@remote
46
+ end
47
+
48
+
49
+ def to_s
50
+ name
51
+ end
52
+
53
+
54
+ def logger
55
+ @lib.logger
56
+ end
57
+
58
+
59
+ def sha
60
+ @sha ||= @lib.sha(name)
61
+ end
62
+
63
+
64
+ def <=>(other)
65
+ self.name <=> other.name
66
+ end
67
+
68
+
69
+ def is_ahead_of(base_branch_name)
70
+ contains_all_of(base_branch_name) and
71
+ (@lib.rev_list(base_branch_name, @name, :oneline => true, :num_revs => 1) != '')
72
+ end
73
+
74
+
75
+ def delete!(force = false)
76
+ if local?
77
+ @lib.branch(@name, :force => force, :delete => true)
78
+ else
79
+ @lib.push(Process.server_name, nil, nil, :delete => @name)
80
+ end
81
+ end
82
+
83
+
84
+ def rename(new_name)
85
+ @lib.branch(@name, :rename => new_name)
86
+ end
87
+
88
+
89
+ def upstream(upstream_name)
90
+ @lib.branch(@name, :upstream => upstream_name)
91
+ end
92
+
93
+
94
+ def contains_all_of(branch_name)
95
+ @lib.rev_list(@name, branch_name, :oneline => true, :num_revs => 1) == ''
96
+ end
97
+
98
+
99
+ def checkout_to_new(new_branch, opts = {})
100
+ @lib.checkout(new_branch, :new_branch => @name, :no_track => opts[:no_track])
101
+ end
102
+
103
+ end
104
+
105
+ end