gitcycle 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/README.md +1 -1
- data/gitcycle.gemspec +1 -1
- data/lib/gitcycle/branch.rb +77 -0
- data/lib/gitcycle/checkout.rb +92 -0
- data/lib/gitcycle/commit.rb +44 -0
- data/lib/gitcycle/discuss.rb +36 -0
- data/lib/gitcycle/incident.rb +115 -0
- data/lib/gitcycle/open.rb +32 -0
- data/lib/gitcycle/pull.rb +56 -0
- data/lib/gitcycle/push.rb +24 -0
- data/lib/gitcycle/qa.rb +204 -0
- data/lib/gitcycle/ready.rb +37 -0
- data/lib/gitcycle/review.rb +29 -0
- data/lib/gitcycle/setup.rb +11 -0
- data/lib/gitcycle.rb +43 -612
- data/spec/config/gitcycle.example.yml +2 -0
- data/spec/gitcycle/incident_spec.rb +13 -0
- data/spec/gitcycle_spec.rb +7 -0
- data/spec/spec_helper.rb +20 -0
- metadata +189 -140
- checksums.yaml +0 -7
data/.gitignore
CHANGED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
gitcycle
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ree-1.8.7-2012.02
|
data/README.md
CHANGED
data/gitcycle.gemspec
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Branch
|
3
|
+
|
4
|
+
def branch(*args)
|
5
|
+
url = args.detect { |arg| arg =~ /^https?:\/\// }
|
6
|
+
title = args.detect { |arg| arg =~ /\s/ }
|
7
|
+
|
8
|
+
exec_git(:branch, args) unless url || title
|
9
|
+
|
10
|
+
require_git && require_config
|
11
|
+
|
12
|
+
params = {
|
13
|
+
'branch[source]' => branches(:current => true)
|
14
|
+
}
|
15
|
+
|
16
|
+
if url && url.include?('lighthouseapp.com/')
|
17
|
+
params.merge!('branch[lighthouse_url]' => url)
|
18
|
+
elsif url && url.include?('github.com/')
|
19
|
+
params.merge!('branch[issue_url]' => url)
|
20
|
+
elsif url
|
21
|
+
puts "Gitcycle only supports Lighthouse or Github Issue URLs.".red
|
22
|
+
exit ERROR[:unrecognized_url]
|
23
|
+
elsif title
|
24
|
+
params.merge!(
|
25
|
+
'branch[name]' => title,
|
26
|
+
'branch[title]' => title
|
27
|
+
)
|
28
|
+
else
|
29
|
+
exec_git(:branch, args)
|
30
|
+
end
|
31
|
+
|
32
|
+
unless yes?("\nYour work will eventually merge into '#{params['branch[source]']}'. Is this correct?")
|
33
|
+
params['branch[source]'] = q("What branch would you like to eventually merge into?")
|
34
|
+
end
|
35
|
+
|
36
|
+
source = params['branch[source]']
|
37
|
+
|
38
|
+
puts "\nRetrieving branch information from gitcycle.\n".green
|
39
|
+
branch = get('branch', params)
|
40
|
+
name = branch['name']
|
41
|
+
|
42
|
+
begin
|
43
|
+
owner, repo = branch['repo'].split(':')
|
44
|
+
branch['home'] ||= @git_login
|
45
|
+
|
46
|
+
unless yes?("Would you like to name your branch '#{name}'?")
|
47
|
+
name = q("\nWhat would you like to name your branch?")
|
48
|
+
name = name.gsub(/[\s\W]/, '-')
|
49
|
+
end
|
50
|
+
|
51
|
+
checkout_remote_branch(
|
52
|
+
:owner => owner,
|
53
|
+
:repo => repo,
|
54
|
+
:branch => branch['source'],
|
55
|
+
:target => name
|
56
|
+
)
|
57
|
+
|
58
|
+
puts "Sending branch information to gitcycle.".green
|
59
|
+
get('branch',
|
60
|
+
'branch[home]' => branch['home'],
|
61
|
+
'branch[name]' => branch['name'],
|
62
|
+
'branch[rename]' => name != branch['name'] ? name : nil,
|
63
|
+
'branch[source]' => branch['source']
|
64
|
+
)
|
65
|
+
rescue SystemExit, Interrupt
|
66
|
+
puts "\nDeleting branch from gitcycle.\n".green
|
67
|
+
get('branch',
|
68
|
+
'branch[name]' => branch['name'],
|
69
|
+
'create' => 0,
|
70
|
+
'reset' => 1
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
puts "\n"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Checkout
|
3
|
+
|
4
|
+
def checkout(*args)
|
5
|
+
if args.length != 1 || options?(args)
|
6
|
+
exec_git(:checkout, args)
|
7
|
+
end
|
8
|
+
|
9
|
+
require_git && require_config
|
10
|
+
|
11
|
+
if args[0] =~ /^https?:\/\//
|
12
|
+
puts "\nRetrieving branch information from gitcycle.\n".green
|
13
|
+
branch = get('branch', 'branch[lighthouse_url]' => args[0], 'create' => 0)
|
14
|
+
if branch
|
15
|
+
checkout_or_track(:name => branch['name'], :remote => 'origin')
|
16
|
+
else
|
17
|
+
puts "\nBranch not found!\n".red
|
18
|
+
puts "\nDid you mean: gitc branch #{args[0]}\n".yellow
|
19
|
+
end
|
20
|
+
elsif args[0] =~ /^\d*$/
|
21
|
+
puts "\nLooking for a branch for LH ticket ##{args[0]}.\n".green
|
22
|
+
results = branches(:array => true).select {|b| b.include?("-#{args[0]}-") }
|
23
|
+
if results.size == 0
|
24
|
+
puts "\nNo matches for ticket ##{args[0]} found.\n".red
|
25
|
+
elsif results.size == 1
|
26
|
+
branch = results.first
|
27
|
+
if branch.strip == branches(:current => true).strip
|
28
|
+
puts "Already on Github branch for LH ticket ##{args[0]} (#{branch})".yellow
|
29
|
+
else
|
30
|
+
puts "\nSwitching to branch '#{branch}'\n".green
|
31
|
+
run("git checkout #{branch}")
|
32
|
+
end
|
33
|
+
else
|
34
|
+
puts "\nFound #{results.size} matches with that LH ticket number:\n".yellow
|
35
|
+
puts results
|
36
|
+
puts "\nDid not switch branches. Please check your ticket number.\n".red
|
37
|
+
end
|
38
|
+
else
|
39
|
+
remote, branch = args[0].split('/')
|
40
|
+
remote, branch = nil, remote if branch.nil?
|
41
|
+
collab = branch && remote
|
42
|
+
|
43
|
+
unless branches(:match => branch)
|
44
|
+
og_remote = nil
|
45
|
+
|
46
|
+
puts "\nRetrieving repo information from gitcycle.\n".green
|
47
|
+
repo = get('repo')
|
48
|
+
remote = repo['owner'] unless collab
|
49
|
+
|
50
|
+
output = add_remote_and_fetch(
|
51
|
+
:catch => false,
|
52
|
+
:owner => remote,
|
53
|
+
:repo => @git_repo
|
54
|
+
)
|
55
|
+
|
56
|
+
if errored?(output)
|
57
|
+
og_remote = remote
|
58
|
+
remote = repo["owner"]
|
59
|
+
|
60
|
+
add_remote_and_fetch(
|
61
|
+
:owner => remote,
|
62
|
+
:repo => @git_repo
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
puts "Creating branch '#{branch}' from '#{remote}/#{branch}'.\n".green
|
67
|
+
output = run("git branch --no-track #{branch} #{remote}/#{branch}", :catch => false)
|
68
|
+
|
69
|
+
if errored?(output)
|
70
|
+
puts "Could not find branch #{"'#{og_remote}/#{branch}' or " if og_remote}'#{remote}/#{branch}'.\n".red
|
71
|
+
exit ERROR[:could_not_find_branch]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if collab
|
76
|
+
puts "Sending branch information to gitcycle.".green
|
77
|
+
get('branch',
|
78
|
+
'branch[home]' => remote,
|
79
|
+
'branch[name]' => branch,
|
80
|
+
'branch[source]' => branch,
|
81
|
+
'branch[collab]' => 1,
|
82
|
+
'create' => 1
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
puts "Checking out '#{branch}'.\n".green
|
87
|
+
run("git checkout -q #{branch}")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
alias :co :checkout
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Commit
|
3
|
+
|
4
|
+
def commit(*args)
|
5
|
+
msg = nil
|
6
|
+
no_add = args.delete("--no-add")
|
7
|
+
|
8
|
+
if args.empty?
|
9
|
+
require_git && require_config
|
10
|
+
|
11
|
+
puts "\nRetrieving branch information from gitcycle.\n".green
|
12
|
+
branch = get('branch',
|
13
|
+
'branch[name]' => branches(:current => true),
|
14
|
+
'create' => 0
|
15
|
+
)
|
16
|
+
|
17
|
+
id = branch["lighthouse_url"].match(/tickets\/(\d+)/)[1] rescue nil
|
18
|
+
|
19
|
+
if branch && id
|
20
|
+
msg = "[##{id}]"
|
21
|
+
msg += " #{branch["title"]}" if branch["title"]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
if no_add
|
26
|
+
cmd = "git commit"
|
27
|
+
else
|
28
|
+
cmd = "git add . && git add . -u && git commit -a"
|
29
|
+
end
|
30
|
+
|
31
|
+
if File.exists?("#{Dir.pwd}/.git/MERGE_HEAD")
|
32
|
+
Kernel.exec(cmd)
|
33
|
+
elsif msg
|
34
|
+
run(cmd + " -m #{msg.dump.gsub('`', "'")}")
|
35
|
+
Kernel.exec("git commit --amend")
|
36
|
+
elsif args.empty?
|
37
|
+
Kernel.exec(cmd)
|
38
|
+
else
|
39
|
+
exec_git(:commit, args)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
alias :ci :commit
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Discuss
|
3
|
+
|
4
|
+
def discuss(*issues)
|
5
|
+
require_git && require_config
|
6
|
+
|
7
|
+
if issues.empty?
|
8
|
+
branch = create_pull_request
|
9
|
+
|
10
|
+
if branch == false
|
11
|
+
puts "Branch not found.\n".red
|
12
|
+
elsif branch['issue_url']
|
13
|
+
puts "\nLabeling issue as 'Discuss'.\n".green
|
14
|
+
get('label',
|
15
|
+
'branch[name]' => branch['name'],
|
16
|
+
'labels' => [ 'Discuss' ]
|
17
|
+
)
|
18
|
+
|
19
|
+
puts "Opening issue: #{branch['issue_url']}\n".green
|
20
|
+
Launchy.open(branch['issue_url'])
|
21
|
+
else
|
22
|
+
puts "You must push code before opening a pull request.\n".red
|
23
|
+
end
|
24
|
+
else
|
25
|
+
puts "\nRetrieving branch information from gitcycle.\n".green
|
26
|
+
|
27
|
+
get('branch', 'issues' => issues, 'scope' => 'repo').each do |branch|
|
28
|
+
if branch['issue_url']
|
29
|
+
puts "Opening issue: #{branch['issue_url']}\n".green
|
30
|
+
Launchy.open(branch['issue_url'])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Incident
|
3
|
+
|
4
|
+
def incident(*args)
|
5
|
+
puts "\nRetrieving statuspage.io information from gitcycle.\n".green
|
6
|
+
|
7
|
+
statuspage = get('statuspage')
|
8
|
+
components = statuspage['components']
|
9
|
+
incidents = statuspage['incidents']
|
10
|
+
page = statuspage['page']
|
11
|
+
|
12
|
+
incident_statuses = %w(investigating identified monitoring resolved)
|
13
|
+
incident_colors = %w(red yellow yellow green)
|
14
|
+
|
15
|
+
component_statuses = %w(operational degraded_performance partial_outage major_outage)
|
16
|
+
component_colors = %w(green yellow yellow red)
|
17
|
+
|
18
|
+
puts_statuses(incidents, incident_statuses, incident_colors)
|
19
|
+
|
20
|
+
incident = q "\n#{"Incident #?".yellow} (press enter for new incident)"
|
21
|
+
|
22
|
+
if incident.strip == ""
|
23
|
+
incident = {}
|
24
|
+
new_incident = q "#{"New incident name?".yellow} (required)"
|
25
|
+
else
|
26
|
+
incident = incidents[incident.to_i]
|
27
|
+
end
|
28
|
+
|
29
|
+
unless incident['id'] || new_incident
|
30
|
+
puts "Incident not found."
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
|
34
|
+
puts_names(incident_statuses, incident_colors)
|
35
|
+
|
36
|
+
incident_status = q "\n#{"Incident status #?".yellow} (required)"
|
37
|
+
incident_body = q "\n#{"Describe the incident".yellow} (enter for none)"
|
38
|
+
|
39
|
+
incident_status = incident_statuses[incident_status.to_i]
|
40
|
+
|
41
|
+
unless incident_status
|
42
|
+
puts "Incident status not found."
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
|
46
|
+
puts_statuses(components, component_statuses, component_colors)
|
47
|
+
|
48
|
+
component = q "\n#{"Service #?".yellow} (required)"
|
49
|
+
component = components[component.to_i]
|
50
|
+
|
51
|
+
unless component
|
52
|
+
puts "Service not found."
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
|
56
|
+
puts_names(component_statuses, component_colors)
|
57
|
+
|
58
|
+
component_status = q "\n#{"Service status #?".yellow} (required)"
|
59
|
+
component_status = component_statuses[component_status.to_i]
|
60
|
+
|
61
|
+
unless component_status
|
62
|
+
puts "Component status not found."
|
63
|
+
exit
|
64
|
+
end
|
65
|
+
|
66
|
+
params = {
|
67
|
+
:new_incident => new_incident,
|
68
|
+
:incident => incident['id'],
|
69
|
+
:component => component['id'],
|
70
|
+
:component_status => component_status,
|
71
|
+
:incident_status => incident_status,
|
72
|
+
:incident_body => incident_body
|
73
|
+
}
|
74
|
+
|
75
|
+
puts "\nUpdating statuspage.io...".green
|
76
|
+
get('statuspage/update', params)
|
77
|
+
|
78
|
+
puts "\nSuccess!\n".green
|
79
|
+
|
80
|
+
sleep 0.5
|
81
|
+
Launchy.open("http://#{page['subdomain']}.statuspage.io")
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def format_name(name)
|
87
|
+
name.gsub(/_/, ' ').capitalize
|
88
|
+
end
|
89
|
+
|
90
|
+
def longest_name(array)
|
91
|
+
array.map { |a| a['name'].length }.max
|
92
|
+
end
|
93
|
+
|
94
|
+
def puts_names(array, colors)
|
95
|
+
puts ""
|
96
|
+
|
97
|
+
array.each_with_index do |a, i|
|
98
|
+
puts "[#{i}] #{format_name(a).send(colors[i])}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def puts_statuses(array, statuses, colors)
|
103
|
+
longest = longest_name(array)
|
104
|
+
puts ""
|
105
|
+
|
106
|
+
array.each_with_index do |a, i|
|
107
|
+
name = a['name']
|
108
|
+
status = a['status']
|
109
|
+
status = format_name(status).send(colors[statuses.index(status)])
|
110
|
+
|
111
|
+
puts "[#{i}] #{name} #{" " * (longest - name.length)} #{status}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Open
|
3
|
+
|
4
|
+
def open(*issues)
|
5
|
+
require_git && require_config
|
6
|
+
|
7
|
+
if issues.empty?
|
8
|
+
branch = create_pull_request
|
9
|
+
|
10
|
+
if branch == false
|
11
|
+
puts "Branch not found.\n".red
|
12
|
+
elsif branch['issue_url']
|
13
|
+
puts "\nOpening the pull request in GitHub\n".green
|
14
|
+
|
15
|
+
puts "Opening issue: #{branch['issue_url']}\n".green
|
16
|
+
Launchy.open(branch['issue_url'])
|
17
|
+
else
|
18
|
+
puts "You must push code before opening a pull request.\n".red
|
19
|
+
end
|
20
|
+
else
|
21
|
+
puts "\nRetrieving branch information from gitcycle.\n".green
|
22
|
+
|
23
|
+
get('branch', 'issues' => issues, 'scope' => 'repo').each do |branch|
|
24
|
+
if branch['issue_url']
|
25
|
+
puts "Opening issue: #{branch['issue_url']}\n".green
|
26
|
+
Launchy.open(branch['issue_url'])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Pull
|
3
|
+
|
4
|
+
def pull(*args)
|
5
|
+
exec_git(:pull, args) if args.length > 0
|
6
|
+
|
7
|
+
require_git && require_config
|
8
|
+
|
9
|
+
current_branch = branches(:current => true)
|
10
|
+
|
11
|
+
puts "\nRetrieving branch information from gitcycle.\n".green
|
12
|
+
branch = get('branch',
|
13
|
+
'branch[name]' => current_branch,
|
14
|
+
'include' => [ 'repo' ],
|
15
|
+
'create' => 0
|
16
|
+
)
|
17
|
+
|
18
|
+
if branch && branch['collab']
|
19
|
+
# Merge from collab
|
20
|
+
merge_remote_branch(
|
21
|
+
:owner => owner = branch['home'],
|
22
|
+
:repo => branch['repo']['name'],
|
23
|
+
:branch => branch['source']
|
24
|
+
)
|
25
|
+
elsif branch
|
26
|
+
# Merge from upstream source branch
|
27
|
+
merge_remote_branch(
|
28
|
+
:owner => owner = branch['repo']['owner'],
|
29
|
+
:repo => branch['repo']['name'],
|
30
|
+
:branch => branch['source']
|
31
|
+
)
|
32
|
+
else
|
33
|
+
puts "\nRetrieving repo information from gitcycle.\n".green
|
34
|
+
repo = get('repo')
|
35
|
+
|
36
|
+
# Merge from upstream branch with same name
|
37
|
+
merge_remote_branch(
|
38
|
+
:owner => owner = repo['owner'],
|
39
|
+
:repo => repo['name'],
|
40
|
+
:branch => current_branch
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
unless branch && branch['collab'] || owner == @git_login
|
45
|
+
# Merge from origin
|
46
|
+
merge_remote_branch(
|
47
|
+
:owner => @git_login,
|
48
|
+
:repo => @git_repo,
|
49
|
+
:branch => current_branch
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
branch
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Gitcycle
|
2
|
+
module Push
|
3
|
+
|
4
|
+
def push(*args)
|
5
|
+
exec_git(:push, args) if args.length > 0
|
6
|
+
|
7
|
+
require_git && require_config
|
8
|
+
|
9
|
+
branch = pull
|
10
|
+
|
11
|
+
if branch && branch['collab']
|
12
|
+
puts "\nPushing branch '#{branch['home']}/#{branch['name']}'.\n".green
|
13
|
+
run("git push #{branch['home']} #{branch['name']} -q")
|
14
|
+
elsif branch
|
15
|
+
puts "\nPushing branch 'origin/#{branch['name']}'.\n".green
|
16
|
+
run("git push origin #{branch['name']} -q")
|
17
|
+
else
|
18
|
+
current_branch = branches(:current => true)
|
19
|
+
puts "\nPushing branch 'origin/#{current_branch}'.\n".green
|
20
|
+
run("git push origin #{current_branch} -q")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|