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 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