gitcycle 0.3.3 → 0.3.4
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/.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
|