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 CHANGED
@@ -6,4 +6,5 @@ features/config/config.yml
6
6
  features/fixtures
7
7
  Gemfile.lock
8
8
  pkg
9
+ spec/config/gitcycle.yml
9
10
  tmp
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
@@ -1,7 +1,7 @@
1
1
  Gitcycle
2
2
  ========
3
3
 
4
- Tame your development cycle.
4
+ Development cycle automation.
5
5
 
6
6
  About
7
7
  -----
data/gitcycle.gemspec CHANGED
@@ -6,7 +6,7 @@ $:.unshift lib unless $:.include?(lib)
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "gitcycle"
9
- s.version = '0.3.3'
9
+ s.version = '0.3.4'
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.authors = [ 'Winton Welsh' ]
12
12
  s.email = [ 'mail@wintoni.us' ]
@@ -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