socialcast-git-extensions 2.3.11 → 3.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/cleanup +5 -0
- data/bin/git-integrate +3 -14
- data/bin/git-nuke +5 -0
- data/bin/git-release +3 -17
- data/bin/git-reviewrequest +3 -76
- data/bin/git-share +3 -8
- data/bin/git-start +3 -22
- data/bin/git-track +3 -6
- data/bin/git-update +3 -10
- data/lib/socialcast-git-extensions.rb +7 -16
- data/lib/socialcast-git-extensions/cli.rb +198 -0
- data/lib/socialcast-git-extensions/git.rb +71 -42
- data/lib/socialcast-git-extensions/github.rb +38 -10
- data/lib/socialcast-git-extensions/string_ext.rb +4 -0
- data/lib/socialcast-git-extensions/version.rb +1 -1
- data/socialcast-git-extensions.gemspec +1 -1
- metadata +76 -36
- data/bin/git-promote +0 -16
- data/bin/git-prune-merged +0 -23
- data/bin/git-reset-prototype +0 -8
- data/bin/git-reset-staging +0 -8
data/bin/cleanup
ADDED
data/bin/git-integrate
CHANGED
@@ -1,16 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
8
|
-
include Socialcast::Git
|
9
|
-
|
10
|
-
branch = current_branch
|
11
|
-
protect_reserved_branches!(branch, 'integrate')
|
12
|
-
|
13
|
-
run_cmd 'git update'
|
14
|
-
integrate(branch, 'prototype')
|
15
|
-
|
16
|
-
share "#worklog integrating #{branch} into prototype #scgitx"
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
|
4
|
+
script = Socialcast::Gitx::CLI.new
|
5
|
+
script.invoke(:integrate, ARGV)
|
data/bin/git-nuke
ADDED
data/bin/git-release
CHANGED
@@ -1,19 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
4
|
-
|
5
|
-
|
6
|
-
branch = current_branch
|
7
|
-
protect_reserved_branches!(branch, 'release')
|
8
|
-
|
9
|
-
exit unless HighLine.agree("<%= color('Release #{branch} to production? (y/n)', :green) %>")
|
10
|
-
|
11
|
-
run_cmd 'git update'
|
12
|
-
integrate branch, 'master'
|
13
|
-
|
14
|
-
integrate branch, 'staging'
|
15
|
-
integrate 'staging', 'prototype'
|
16
|
-
run_cmd "git checkout master"
|
17
|
-
run_cmd "grb rm #{branch}"
|
18
|
-
|
19
|
-
share "#worklog releasing #{branch} to production #scgitx"
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
|
4
|
+
script = Socialcast::Gitx::CLI.new
|
5
|
+
script.invoke(:release)
|
data/bin/git-reviewrequest
CHANGED
@@ -1,78 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
8
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'string_ext.rb')
|
9
|
-
include Socialcast::Git
|
10
|
-
include Socialcast::Github
|
11
|
-
|
12
|
-
branch = current_branch
|
13
|
-
username = `git config -z --global --get github.user`.strip
|
14
|
-
password = HighLine.ask("Github password: ") { |q| q.echo = false }
|
15
|
-
|
16
|
-
run_cmd 'git update'
|
17
|
-
|
18
|
-
description = ""
|
19
|
-
if index = (ARGV.index('-d') || ARGV.index('--description'))
|
20
|
-
description = ARGV[index + 1]
|
21
|
-
if description.nil?
|
22
|
-
puts "Usage: #git-reviewrequest -d <description>"
|
23
|
-
exit 1
|
24
|
-
end
|
25
|
-
else
|
26
|
-
require 'tempfile'
|
27
|
-
Tempfile.open('reviewrequest.md') do |f|
|
28
|
-
helper_tip = <<-EOS.dedent
|
29
|
-
# Describe your pull request
|
30
|
-
# Use GitHub flavored Markdown http://github.github.com/github-flavored-markdown/
|
31
|
-
# Why not include a screenshot? Format is ![title](url)
|
32
|
-
EOS
|
33
|
-
f << "\n\n#{helper_tip}"
|
34
|
-
f.flush
|
35
|
-
|
36
|
-
editor = ENV['EDITOR'] || 'vi'
|
37
|
-
flags = case editor
|
38
|
-
when 'mate', 'emacs'
|
39
|
-
'-w'
|
40
|
-
when 'mvim'
|
41
|
-
'-f'
|
42
|
-
else
|
43
|
-
''
|
44
|
-
end
|
45
|
-
pid = fork { exec "#{editor} #{flags} #{f.path}" }
|
46
|
-
Process.waitpid(pid)
|
47
|
-
description = File.read(f.path)
|
48
|
-
description = description.gsub(/^\#.*/, '').chomp.strip
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
short_description = description.split("\n").first(5).join("\n")
|
53
|
-
changes = `git diff --stat origin/master...#{branch}`.split("\n")
|
54
|
-
stats = changes.pop
|
55
|
-
if changes.length > 5
|
56
|
-
dirs = changes.map do |file_change|
|
57
|
-
filename = "#{file_change.split.first}"
|
58
|
-
dir = filename.gsub(/\/[^\/]+$/, '')
|
59
|
-
dir
|
60
|
-
end
|
61
|
-
dir_counts = Hash.new(0)
|
62
|
-
dirs.each {|dir| dir_counts[dir] += 1 }
|
63
|
-
changes = dir_counts.to_a.sort_by {|k,v| v}.reverse.first(5).map {|k,v| "#{k} (#{v} file#{'s' if v > 1})"}
|
64
|
-
end
|
65
|
-
change_summary = (changes + [stats]).join("\n")
|
66
|
-
|
67
|
-
repo = `git config -z --get remote.origin.url`.strip
|
68
|
-
# ex: git@github.com:socialcast/socialcast-git-extensions.git
|
69
|
-
repo = repo.scan(/:(.+\/.+)\./).first.first
|
70
|
-
url = create_pull_request username, password, branch, repo, description
|
71
|
-
|
72
|
-
if url
|
73
|
-
review_message = ["@SocialcastDevelopers #reviewrequest for #{branch} #scgitx", short_description, change_summary].join("\n\n")
|
74
|
-
share review_message, {:url => url, :message_type => 'review_request'}
|
75
|
-
else
|
76
|
-
HighLine.say "Skipping socialcast announcement"
|
77
|
-
exit 1
|
78
|
-
end
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
|
4
|
+
script = Socialcast::Gitx::CLI.new
|
5
|
+
script.invoke(:reviewrequest, ARGV)
|
data/bin/git-share
CHANGED
@@ -1,10 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
8
|
-
include Socialcast::Git
|
9
|
-
|
10
|
-
run_cmd "grb publish #{current_branch}"
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
|
4
|
+
script = Socialcast::Gitx::CLI.new
|
5
|
+
script.invoke(:share, ARGV)
|
data/bin/git-start
CHANGED
@@ -1,24 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
include Socialcast::Git
|
7
|
-
|
8
|
-
unless branch_name = ARGV.first
|
9
|
-
example_branch = %w{ api-fix-invalid-auth desktop-cleanup-avatar-markup share-form-add-edit-link }.sort_by { rand }.first
|
10
|
-
repo = Grit::Repo.new(Dir.pwd)
|
11
|
-
remote_branches = repo.remotes.collect {|b| b.name.split('/').last }
|
12
|
-
until branch_name = HighLine.ask("What would you like to name your branch? (ex: #{example_branch})") {|q|
|
13
|
-
q.validate = Proc.new { |branch|
|
14
|
-
branch =~ /^[A-Za-z0-9\-_]+$/ && !remote_branches.include?(branch)
|
15
|
-
}
|
16
|
-
}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
run_cmd 'git checkout master'
|
21
|
-
run_cmd 'git pull'
|
22
|
-
run_cmd "git checkout -b #{branch_name}"
|
23
|
-
|
24
|
-
share "#worklog starting work on #{branch_name} #scgitx"
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
|
4
|
+
script = Socialcast::Gitx::CLI.new
|
5
|
+
script.invoke(:start, ARGV)
|
data/bin/git-track
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
4
|
-
|
5
|
-
|
6
|
-
branch = current_branch
|
7
|
-
|
8
|
-
run_cmd "git branch --set-upstream #{branch} origin/#{branch}"
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
|
4
|
+
script = Socialcast::Gitx::CLI.new
|
5
|
+
script.invoke(:track, ARGV)
|
data/bin/git-update
CHANGED
@@ -1,12 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
4
|
-
|
5
|
-
|
6
|
-
branch = current_branch
|
7
|
-
|
8
|
-
HighLine.say "updating <%= color('#{branch}', :green) %> to have most recent changes from master"
|
9
|
-
run_cmd "git pull origin #{branch}" rescue nil
|
10
|
-
run_cmd 'git pull origin master'
|
11
|
-
run_cmd 'git push origin HEAD'
|
12
|
-
run_cmd 'git remote prune origin'
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
|
4
|
+
script = Socialcast::Gitx::CLI.new
|
5
|
+
script.invoke(:update, ARGV)
|
@@ -1,25 +1,16 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
2
|
+
require 'socialcast-git-extensions/version'
|
3
|
+
require 'socialcast-git-extensions/string_ext'
|
4
|
+
require 'socialcast-git-extensions/git'
|
5
|
+
require 'socialcast-git-extensions/github'
|
3
6
|
|
4
7
|
module Socialcast
|
5
8
|
module Gitx
|
6
|
-
|
7
|
-
abort("Cannot #{mode} reserved branch") if Socialcast::Git::RESERVED_BRANCHES.include?(branch)
|
8
|
-
end
|
9
|
+
# execute a shell command and raise an error if non-zero exit code is returned
|
9
10
|
def run_cmd(cmd)
|
10
|
-
|
11
|
+
say "\n> "
|
12
|
+
say cmd.gsub("'", ''), :red
|
11
13
|
raise "#{cmd} failed" unless system cmd
|
12
14
|
end
|
13
|
-
def share(message, options = {})
|
14
|
-
return if ARGV.delete("--quiet") || ARGV.delete("-q")
|
15
|
-
require 'socialcast'
|
16
|
-
require 'socialcast/message'
|
17
|
-
Socialcast::Message.configure_from_credentials
|
18
|
-
Socialcast::Message.create options.merge(:body => message)
|
19
|
-
say "Message has been shared"
|
20
|
-
end
|
21
15
|
end
|
22
16
|
end
|
23
|
-
|
24
|
-
require 'socialcast-git-extensions/git'
|
25
|
-
require 'socialcast-git-extensions/github'
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require "thor"
|
2
|
+
require 'rest_client'
|
3
|
+
require 'socialcast-git-extensions'
|
4
|
+
|
5
|
+
module Socialcast
|
6
|
+
module Gitx
|
7
|
+
class CLI < Thor
|
8
|
+
include Socialcast::Gitx
|
9
|
+
include Socialcast::Gitx::Git
|
10
|
+
include Socialcast::Gitx::Github
|
11
|
+
|
12
|
+
BASE_BRANCH = 'master'
|
13
|
+
PULL_REQUEST_DESCRIPTION = "\n\n" + <<-EOS.dedent
|
14
|
+
# Describe your pull request
|
15
|
+
# Use GitHub flavored Markdown http://github.github.com/github-flavored-markdown/
|
16
|
+
# Why not include a screenshot? Format is ![title](url)
|
17
|
+
EOS
|
18
|
+
|
19
|
+
method_option :quiet, :type => :boolean, :aliases => '-q'
|
20
|
+
method_option :trace, :type => :boolean, :aliases => '-v'
|
21
|
+
def initialize(*args)
|
22
|
+
super(*args)
|
23
|
+
RestClient.proxy = ENV['HTTPS_PROXY'] if ENV.has_key?('HTTPS_PROXY')
|
24
|
+
RestClient.log = Logger.new(STDOUT) if options[:trace]
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "reviewrequest", "Create a pull request on github"
|
28
|
+
method_option :description, :type => :string, :aliases => '-d', :desc => 'pull request description'
|
29
|
+
# @see http://developer.github.com/v3/pulls/
|
30
|
+
def reviewrequest
|
31
|
+
token = authorization_token
|
32
|
+
|
33
|
+
update
|
34
|
+
|
35
|
+
description = options[:description] || editor_input(PULL_REQUEST_DESCRIPTION)
|
36
|
+
branch = current_branch
|
37
|
+
repo = current_repo
|
38
|
+
create_pull_request token, branch, repo, description
|
39
|
+
|
40
|
+
short_description = description.split("\n").first(5).join("\n")
|
41
|
+
review_message = ["@SocialcastDevelopers #reviewrequest for #{branch} #scgitx", short_description, changelog_summary(branch)].join("\n\n")
|
42
|
+
post review_message, {:url => url, :message_type => 'review_request'}
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'update', 'Update the current branch with latest upstream changes'
|
46
|
+
def update
|
47
|
+
branch = current_branch
|
48
|
+
|
49
|
+
say 'updating '
|
50
|
+
say "#{branch} ", :green
|
51
|
+
say "to have most recent changes from "
|
52
|
+
say BASE_BRANCH, :green
|
53
|
+
|
54
|
+
run_cmd "git pull origin #{branch}" rescue nil
|
55
|
+
run_cmd "git pull origin #{BASE_BRANCH}"
|
56
|
+
run_cmd 'git push origin HEAD'
|
57
|
+
run_cmd 'git remote prune origin'
|
58
|
+
end
|
59
|
+
|
60
|
+
desc 'cleanup', 'Cleanup branches that have been merged into master from the repo'
|
61
|
+
def cleanup
|
62
|
+
run_cmd "git checkout #{BASE_BRANCH}"
|
63
|
+
run_cmd "git pull"
|
64
|
+
|
65
|
+
say "Deleting branches that have been merged into "
|
66
|
+
say BASE_BRANCH, :green
|
67
|
+
branches(:merged => true).each do |branch|
|
68
|
+
run_cmd "git branch -d #{branch}"
|
69
|
+
end
|
70
|
+
branches(:merged => true, :remote => true).each do |branch|
|
71
|
+
run_cmd "grb rm #{branch}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
desc 'track', 'set the current branch to track the remote branch with the same name'
|
76
|
+
def track
|
77
|
+
branch = current_branch
|
78
|
+
run_cmd "git branch --set-upstream #{branch} origin/#{branch}"
|
79
|
+
end
|
80
|
+
|
81
|
+
desc 'start', 'start a new git branch with latest changes from master'
|
82
|
+
def start(branch_name = nil)
|
83
|
+
unless branch_name
|
84
|
+
example_branch = %w{ api-fix-invalid-auth desktop-cleanup-avatar-markup share-form-add-edit-link }.sort_by { rand }.first
|
85
|
+
repo = Grit::Repo.new(Dir.pwd)
|
86
|
+
remote_branches = repo.remotes.collect {|b| b.name.split('/').last }
|
87
|
+
until branch_name = ask("What would you like to name your branch? (ex: #{example_branch})") {|q|
|
88
|
+
q.validate = Proc.new { |branch|
|
89
|
+
branch =~ /^[A-Za-z0-9\-_]+$/ && !remote_branches.include?(branch)
|
90
|
+
}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
run_cmd "git checkout #{BASE_BRANCH}"
|
96
|
+
run_cmd 'git pull'
|
97
|
+
run_cmd "git checkout -b #{branch_name}"
|
98
|
+
|
99
|
+
post "#worklog starting work on #{branch_name} #scgitx"
|
100
|
+
end
|
101
|
+
|
102
|
+
desc 'share', 'publish the current branch for peer review'
|
103
|
+
def share
|
104
|
+
run_cmd "grb publish #{current_branch}"
|
105
|
+
end
|
106
|
+
|
107
|
+
desc 'integrate', 'integrate the current branch into one of the aggregate development branches'
|
108
|
+
def integrate(target_branch)
|
109
|
+
branch = current_branch
|
110
|
+
|
111
|
+
update
|
112
|
+
integrate_branch(branch, target_branch)
|
113
|
+
integrate_branch(branch, 'prototype') if target_branch == 'staging'
|
114
|
+
|
115
|
+
post "#worklog integrating #{branch} into #{target_branch} #scgitx"
|
116
|
+
end
|
117
|
+
|
118
|
+
desc 'nuke', 'nuke the specified aggregate branch and reset it to a known good state'
|
119
|
+
def nuke(bad_branch, good_branch='last_known_good_master')
|
120
|
+
good_branch = "last_known_good_#{good_branch}" unless good_branch.starts_with?('last_known_good_')
|
121
|
+
removed_branches = reset_branch(bad_branch, good_branch)
|
122
|
+
reset_branch("last_known_good_#{bad_branch}", good_branch)
|
123
|
+
|
124
|
+
post "#worklog resetting #{branch} branch to #{good_branch} #scgitx\n\nthe following branches were affected:\n#{removed_branches.map{|b| '* ' + b}.join("\n") }"
|
125
|
+
end
|
126
|
+
|
127
|
+
desc 'release', 'release the current branch to production'
|
128
|
+
def release
|
129
|
+
branch = current_branch
|
130
|
+
assert_not_protected_branch!(branch, 'release')
|
131
|
+
|
132
|
+
return unless yes?("Release #{branch} to production? (y/n)", :green)
|
133
|
+
|
134
|
+
update
|
135
|
+
integrate branch, 'master'
|
136
|
+
integrate branch, 'staging'
|
137
|
+
run_cmd "git checkout #{BASE_BRANCH}"
|
138
|
+
run_cmd "grb rm #{branch}"
|
139
|
+
|
140
|
+
share "#worklog releasing #{branch} to production #scgitx"
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
# build a summary of changes
|
147
|
+
def changelog_summary(branch)
|
148
|
+
changes = `git diff --stat origin/#{BASE_BRANCH}...#{branch}`.split("\n")
|
149
|
+
stats = changes.pop
|
150
|
+
if changes.length > 5
|
151
|
+
dirs = changes.map do |file_change|
|
152
|
+
filename = "#{file_change.split.first}"
|
153
|
+
dir = filename.gsub(/\/[^\/]+$/, '')
|
154
|
+
dir
|
155
|
+
end
|
156
|
+
dir_counts = Hash.new(0)
|
157
|
+
dirs.each {|dir| dir_counts[dir] += 1 }
|
158
|
+
changes = dir_counts.to_a.sort_by {|k,v| v}.reverse.first(5).map {|k,v| "#{k} (#{v} file#{'s' if v > 1})"}
|
159
|
+
end
|
160
|
+
(changes + [stats]).join("\n")
|
161
|
+
end
|
162
|
+
|
163
|
+
# launch configured editor to retreive message/string
|
164
|
+
def editor_input(initial_text = '')
|
165
|
+
require 'tempfile'
|
166
|
+
Tempfile.open('reviewrequest.md') do |f|
|
167
|
+
f << initial_text
|
168
|
+
f.flush
|
169
|
+
|
170
|
+
editor = ENV['EDITOR'] || 'vi'
|
171
|
+
flags = case editor
|
172
|
+
when 'mate', 'emacs'
|
173
|
+
'-w'
|
174
|
+
when 'mvim'
|
175
|
+
'-f'
|
176
|
+
else
|
177
|
+
''
|
178
|
+
end
|
179
|
+
pid = fork { exec "#{editor} #{flags} #{f.path}" }
|
180
|
+
Process.waitpid(pid)
|
181
|
+
description = File.read(f.path)
|
182
|
+
description.gsub(/^\#.*/, '').chomp.strip
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# post a message in socialcast
|
187
|
+
# skip sharing message if CLI quiet option is present
|
188
|
+
def post(message, params = {})
|
189
|
+
return if options[:quiet]
|
190
|
+
require 'socialcast'
|
191
|
+
require 'socialcast/message'
|
192
|
+
Socialcast::Message.configure_from_credentials
|
193
|
+
Socialcast::Message.create params.merge(:body => message)
|
194
|
+
say "Message has been posted"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -1,56 +1,85 @@
|
|
1
1
|
require 'grit'
|
2
2
|
|
3
3
|
module Socialcast
|
4
|
-
module
|
5
|
-
|
6
|
-
|
4
|
+
module Gitx
|
5
|
+
module Git
|
6
|
+
RESERVED_BRANCHES = %w{ HEAD master staging prototype next_release }
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
Grit::Head.current(repo).name
|
11
|
-
end
|
12
|
-
def branches(options = {})
|
13
|
-
branches = []
|
14
|
-
args = []
|
15
|
-
args << '-r' if options[:remote]
|
16
|
-
args << '--merged' if options[:merged]
|
17
|
-
output = `git branch #{args.join(' ')}`.split("\n")
|
18
|
-
output.each do |branch|
|
19
|
-
branch = branch.gsub(/\*/, '').strip.split(' ').first
|
20
|
-
branch = branch.split('/').last if options[:remote]
|
21
|
-
branches << branch unless RESERVED_BRANCHES.include?(branch)
|
8
|
+
def assert_not_protected_branch!(branch, action)
|
9
|
+
raise "Cannot #{action} reserved branch" if RESERVED_BRANCHES.include?(branch) || aggregate_branch?(branch)
|
22
10
|
end
|
23
|
-
branches.uniq
|
24
|
-
end
|
25
|
-
def reset_branch(branch, head_branch = 'master', options = {})
|
26
|
-
return if branch == head_branch
|
27
11
|
|
28
|
-
|
12
|
+
# lookup the current branch of the PWD
|
13
|
+
def current_branch
|
14
|
+
repo = Grit::Repo.new(Dir.pwd)
|
15
|
+
Grit::Head.current(repo).name
|
16
|
+
end
|
29
17
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
run_cmd "grb publish #{branch}"
|
37
|
-
run_cmd "git checkout #{head_branch}"
|
18
|
+
# lookup the current repository of the PWD
|
19
|
+
# ex: git@github.com:socialcast/socialcast-git-extensions.git
|
20
|
+
def current_repo
|
21
|
+
repo = `git config -z --get remote.origin.url`.strip
|
22
|
+
repo.scan(/:(.+\/.+)\./).first.first
|
23
|
+
end
|
38
24
|
|
39
|
-
|
40
|
-
|
25
|
+
# retrieve a list of branches
|
26
|
+
def branches(options = {})
|
27
|
+
branches = []
|
28
|
+
args = []
|
29
|
+
args << '-r' if options[:remote]
|
30
|
+
args << "--merged #{options[:merged].is_a?(String) ? options[:merged] : ''}" if options[:merged]
|
31
|
+
output = `git branch #{args.join(' ')}`.split("\n")
|
32
|
+
output.each do |branch|
|
33
|
+
branch = branch.gsub(/\*/, '').strip.split(' ').first
|
34
|
+
branch = branch.split('/').last if options[:remote]
|
35
|
+
branches << branch unless RESERVED_BRANCHES.include?(branch)
|
36
|
+
end
|
37
|
+
branches.uniq
|
38
|
+
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
AGGREGATE_BRANCHES = %w{ staging prototype }
|
41
|
+
# reset the specified branch to the same set of commits as the destination branch
|
42
|
+
# used to revert commits on aggregate branches back to a known good state
|
43
|
+
def reset_branch(branch, head_branch)
|
44
|
+
raise "Can not reset #{branch} to #{head_branch}" if branch == head_branch
|
45
|
+
raise "Only aggregate branches are allowed to be reset: #{AGGREGATE_BRANCHES}" unless aggregate_branch?(branch)
|
46
|
+
say "Resetting "
|
47
|
+
say "#{branch} ", :green
|
48
|
+
say "branch to "
|
49
|
+
say head_branch, :green
|
50
|
+
|
51
|
+
run_cmd "git checkout #{head_branch}"
|
52
|
+
run_cmd "git pull"
|
53
|
+
removed_branches = branches(:remote => true, :merged => "origin/#{branch}") - branches(:remote => true, :merged => "origin/#{head_branch}")
|
54
|
+
run_cmd "git branch -D #{branch}" rescue nil
|
55
|
+
run_cmd "git push origin :#{branch}" rescue nil
|
56
|
+
run_cmd "git checkout -b #{branch}"
|
57
|
+
run_cmd "grb publish #{branch}"
|
58
|
+
run_cmd "git checkout #{head_branch}"
|
59
|
+
|
60
|
+
removed_branches
|
61
|
+
end
|
62
|
+
|
63
|
+
# integrate a branch into a destination aggregate branch
|
64
|
+
def integrate_branch(branch, destination_branch = 'staging')
|
65
|
+
assert_not_protected_branch!(branch, 'integrate')
|
66
|
+
raise "Only aggregate branches are allowed for integration: #{AGGREGATE_BRANCHES}" unless aggregate_branch?(destination_branch)
|
67
|
+
say "Integrating "
|
68
|
+
say "#{branch} ", :green
|
69
|
+
say "into "
|
70
|
+
say destination_branch, :green
|
71
|
+
|
72
|
+
run_cmd "git remote prune origin"
|
73
|
+
run_cmd "git checkout #{destination_branch}"
|
74
|
+
run_cmd "git pull . #{branch}"
|
75
|
+
run_cmd "git push origin HEAD"
|
76
|
+
run_cmd "git checkout #{branch}"
|
48
77
|
end
|
49
|
-
run_cmd "git checkout #{destination_branch}"
|
50
|
-
run_cmd "git pull . #{branch}"
|
51
|
-
run_cmd "git push origin HEAD"
|
52
78
|
|
53
|
-
|
79
|
+
private
|
80
|
+
def aggregate_branch?(branch)
|
81
|
+
AGGREGATE_BRANCHES.include?(branch) || branch.starts_with?('last_known_good')
|
82
|
+
end
|
54
83
|
end
|
55
84
|
end
|
56
85
|
end
|
@@ -1,22 +1,50 @@
|
|
1
1
|
require 'rest_client'
|
2
2
|
require 'json'
|
3
|
+
require 'socialcast'
|
3
4
|
|
4
5
|
module Socialcast
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
module Gitx
|
7
|
+
module Github
|
8
|
+
# request github authorization token
|
9
|
+
# store the token in ~/.socialcast/credentials.yml for future reuse
|
10
|
+
# @see http://developer.github.com/v3/oauth/#scopes
|
11
|
+
def authorization_token
|
12
|
+
credentials = Socialcast.credentials
|
13
|
+
return credentials[:scgitx_token] if credentials[:scgitx_token]
|
14
|
+
|
15
|
+
username = `git config -z --global --get github.user`.strip
|
16
|
+
raise "Github user not configured. Run: `git config --global github.user 'me@email.com'`" if username.empty?
|
17
|
+
password = ask("Github password for #{username}: ") { |q| q.echo = false }
|
18
|
+
|
19
|
+
payload = {:scopes => ['repo'], :note => 'Socialcast Git eXtension', :note_url => 'https://github.com/socialcast/socialcast-git-extensions'}.to_json
|
20
|
+
response = RestClient::Request.new(:url => "https://api.github.com/authorizations", :method => "POST", :user => username, :password => password, :payload => payload, :headers => {:accept => :json, :content_type => :json}).execute
|
21
|
+
data = JSON.parse response.body
|
22
|
+
token = data['token']
|
23
|
+
Socialcast.credentials = credentials.merge(:scgitx_token => token)
|
24
|
+
token
|
25
|
+
rescue RestClient::Exception => e
|
26
|
+
data = JSON.parse e.http_body
|
27
|
+
say "Failed to obtain OAuth authorization token: #{data['message']}"
|
28
|
+
throw e
|
29
|
+
end
|
30
|
+
|
31
|
+
# @see http://developer.github.com/v3/pulls/
|
32
|
+
def create_pull_request(token, branch, repo, body)
|
33
|
+
payload = {:title => branch, :base => 'master', :head => branch, :body => body}.to_json
|
34
|
+
say "Creating pull request for "
|
35
|
+
say "#{branch} ", :green
|
36
|
+
say "against "
|
37
|
+
say "master ", :green
|
38
|
+
say "in "
|
39
|
+
say repo, :green
|
40
|
+
response = RestClient::Request.new(:url => "https://api.github.com/repos/#{repo}/pulls", :method => "POST", :payload => payload, :headers => {:accept => :json, :content_type => :json, 'Authorization' => "token #{token}"}).execute
|
12
41
|
data = JSON.parse response.body
|
13
42
|
url = data['html_url']
|
14
43
|
rescue RestClient::Exception => e
|
15
44
|
data = JSON.parse e.http_body
|
16
|
-
|
17
|
-
|
45
|
+
say "Failed to create pull request: #{data['message']}"
|
46
|
+
throw e
|
18
47
|
end
|
19
48
|
end
|
20
49
|
end
|
21
50
|
end
|
22
|
-
|
@@ -16,10 +16,10 @@ Gem::Specification.new do |s|
|
|
16
16
|
|
17
17
|
s.add_runtime_dependency(%q<grit>, [">= 0"])
|
18
18
|
s.add_runtime_dependency(%q<git_remote_branch>, [">= 0"])
|
19
|
-
s.add_runtime_dependency(%q<highline>, [">= 0"])
|
20
19
|
s.add_runtime_dependency(%q<socialcast>, [">= 1.1.4"])
|
21
20
|
s.add_runtime_dependency(%q<rest-client>, [">= 1.4.0"])
|
22
21
|
s.add_runtime_dependency(%q<json_pure>, [">= 0"])
|
22
|
+
s.add_runtime_dependency(%q<thor>, [">= 0"])
|
23
23
|
s.add_development_dependency(%q<rake>, ["0.9.2.2"])
|
24
24
|
s.add_development_dependency(%q<shoulda>, ["2.11.3"])
|
25
25
|
|
metadata
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: socialcast-git-extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 3.0.0.pre
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ryan Sonnek
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: grit
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: git_remote_branch
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,21 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: highline
|
38
|
-
requirement: &2156542060 !ruby/object:Gem::Requirement
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
41
|
none: false
|
40
42
|
requirements:
|
41
43
|
- - ! '>='
|
42
44
|
- !ruby/object:Gem::Version
|
43
45
|
version: '0'
|
44
|
-
type: :runtime
|
45
|
-
prerelease: false
|
46
|
-
version_requirements: *2156542060
|
47
46
|
- !ruby/object:Gem::Dependency
|
48
47
|
name: socialcast
|
49
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
50
49
|
none: false
|
51
50
|
requirements:
|
52
51
|
- - ! '>='
|
@@ -54,10 +53,15 @@ dependencies:
|
|
54
53
|
version: 1.1.4
|
55
54
|
type: :runtime
|
56
55
|
prerelease: false
|
57
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.1.4
|
58
62
|
- !ruby/object:Gem::Dependency
|
59
63
|
name: rest-client
|
60
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
61
65
|
none: false
|
62
66
|
requirements:
|
63
67
|
- - ! '>='
|
@@ -65,10 +69,31 @@ dependencies:
|
|
65
69
|
version: 1.4.0
|
66
70
|
type: :runtime
|
67
71
|
prerelease: false
|
68
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.4.0
|
69
78
|
- !ruby/object:Gem::Dependency
|
70
79
|
name: json_pure
|
71
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: thor
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ! '>='
|
@@ -76,39 +101,52 @@ dependencies:
|
|
76
101
|
version: '0'
|
77
102
|
type: :runtime
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: rake
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
|
-
- - =
|
115
|
+
- - '='
|
86
116
|
- !ruby/object:Gem::Version
|
87
117
|
version: 0.9.2.2
|
88
118
|
type: :development
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - '='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.9.2.2
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: shoulda
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
|
-
- - =
|
131
|
+
- - '='
|
97
132
|
- !ruby/object:Gem::Version
|
98
133
|
version: 2.11.3
|
99
134
|
type: :development
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - '='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 2.11.3
|
102
142
|
description: GIT it done!
|
103
143
|
email:
|
104
144
|
- ryan@socialcast.com
|
105
145
|
executables:
|
146
|
+
- cleanup
|
106
147
|
- git-integrate
|
107
|
-
- git-
|
108
|
-
- git-prune-merged
|
148
|
+
- git-nuke
|
109
149
|
- git-release
|
110
|
-
- git-reset-prototype
|
111
|
-
- git-reset-staging
|
112
150
|
- git-reviewrequest
|
113
151
|
- git-share
|
114
152
|
- git-start
|
@@ -125,12 +163,10 @@ files:
|
|
125
163
|
- LICENSE
|
126
164
|
- README.rdoc
|
127
165
|
- Rakefile
|
166
|
+
- bin/cleanup
|
128
167
|
- bin/git-integrate
|
129
|
-
- bin/git-
|
130
|
-
- bin/git-prune-merged
|
168
|
+
- bin/git-nuke
|
131
169
|
- bin/git-release
|
132
|
-
- bin/git-reset-prototype
|
133
|
-
- bin/git-reset-staging
|
134
170
|
- bin/git-reviewrequest
|
135
171
|
- bin/git-share
|
136
172
|
- bin/git-start
|
@@ -138,6 +174,7 @@ files:
|
|
138
174
|
- bin/git-update
|
139
175
|
- bin/git-wtf
|
140
176
|
- lib/socialcast-git-extensions.rb
|
177
|
+
- lib/socialcast-git-extensions/cli.rb
|
141
178
|
- lib/socialcast-git-extensions/git.rb
|
142
179
|
- lib/socialcast-git-extensions/github.rb
|
143
180
|
- lib/socialcast-git-extensions/string_ext.rb
|
@@ -157,15 +194,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
157
194
|
- - ! '>='
|
158
195
|
- !ruby/object:Gem::Version
|
159
196
|
version: '0'
|
197
|
+
segments:
|
198
|
+
- 0
|
199
|
+
hash: 2945626375834761242
|
160
200
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
201
|
none: false
|
162
202
|
requirements:
|
163
|
-
- - ! '
|
203
|
+
- - ! '>'
|
164
204
|
- !ruby/object:Gem::Version
|
165
|
-
version:
|
205
|
+
version: 1.3.1
|
166
206
|
requirements: []
|
167
207
|
rubyforge_project: socialcast-git-extensions
|
168
|
-
rubygems_version: 1.8.
|
208
|
+
rubygems_version: 1.8.24
|
169
209
|
signing_key:
|
170
210
|
specification_version: 3
|
171
211
|
summary: git extension scripts for socialcast workflow
|
data/bin/git-promote
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
4
|
-
include Socialcast::Git
|
5
|
-
|
6
|
-
branch = current_branch
|
7
|
-
protect_reserved_branches!(branch, 'promote')
|
8
|
-
|
9
|
-
run_cmd 'git update'
|
10
|
-
integrate(branch, 'staging')
|
11
|
-
|
12
|
-
|
13
|
-
integrate('staging', 'prototype')
|
14
|
-
run_cmd "git checkout #{branch}"
|
15
|
-
|
16
|
-
share "#worklog promoting #{branch} into staging #scgitx"
|
data/bin/git-prune-merged
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
#prune branches that have been merged into master from the repo
|
4
|
-
#usage -r --remote to prune remote branches
|
5
|
-
|
6
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
7
|
-
include Socialcast::Git
|
8
|
-
|
9
|
-
remote = ARGV.delete("--remote") || ARGV.delete("-r")
|
10
|
-
|
11
|
-
run_cmd "git checkout master"
|
12
|
-
run_cmd "git pull"
|
13
|
-
|
14
|
-
HighLine.say "Deleting <%= color('#{remote ? 'remote' : 'local'}', :green) %> branches that have been merged into master"
|
15
|
-
branches(:merged => true).each do |branch|
|
16
|
-
run_cmd "git branch -d #{branch}"
|
17
|
-
end
|
18
|
-
|
19
|
-
if remote
|
20
|
-
branches(:merged => true, :remote => true).each do |branch|
|
21
|
-
run_cmd "grb rm #{branch}"
|
22
|
-
end
|
23
|
-
end
|
data/bin/git-reset-prototype
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
4
|
-
include Socialcast::Git
|
5
|
-
|
6
|
-
head_branch = ARGV.first || 'master'
|
7
|
-
reset_branch('prototype', head_branch, :share => true)
|
8
|
-
reset_branch('last_known_good_prototype', head_branch)
|
data/bin/git-reset-staging
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions.rb')
|
4
|
-
include Socialcast::Git
|
5
|
-
|
6
|
-
head_branch = ARGV.first || 'last_known_good_staging'
|
7
|
-
reset_branch('staging', head_branch, :share => (head_branch != 'last_known_good_staging'))
|
8
|
-
reset_branch('last_known_good_staging', head_branch)
|