socialcast-git-extensions 2.3.11 → 3.0.0.pre
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/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 
|
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 
|
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)
|