geordi 1.0.2 → 1.0.3
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.
- checksums.yaml +5 -13
- data/lib/geordi/commands/commit.rb +2 -166
- data/lib/geordi/commands/deploy.rb +12 -38
- data/lib/geordi/commands/security_update.rb +4 -7
- data/lib/geordi/commands/setup_vnc.rb +34 -52
- data/lib/geordi/firefox_for_selenium.rb +11 -15
- data/lib/geordi/gitpt.rb +165 -0
- data/lib/geordi/interaction.rb +15 -7
- data/lib/geordi/util.rb +7 -4
- data/lib/geordi/version.rb +1 -1
- metadata +11 -10
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZDIyN2Y2MTIzODZjZjhiZmUzMWRmNDVjODczYzFhNGZlYzM1MWI5NA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ac4e04e376ff1dbe4d61f1f461ec3babc7336878
|
4
|
+
data.tar.gz: d116626e960d6917d0966555c9605595eff3901b
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YTU2MWI1MGYxZjg4Mjc3NDBjM2YwMmY5YWNiNDBkOTc5M2Y5ZGY0ODAyZjAx
|
11
|
-
NzgyZDQzNTcyZjM4ZTU0OTY2MzllMzM5YjA3YmVhMDY3MDJhODE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NGNjNmUxOGU5MzIyNmM0NWZlN2U0MGUzYmNlNDlmNzM2MjAxOTgzMzE1MmMw
|
14
|
-
MDIyNDZmOTZiMDIxOTBiM2Y4ZjI0YWE2ZTg2MDM5ZmMxNmIzMjA1YzYzOGY0
|
15
|
-
YzhiNmMyOTgwYTY3NDBlNzI1NjhjMTQ0NjRiMzc2MzVhNmQ0YTY=
|
6
|
+
metadata.gz: 99be3db5c23f4f7a162af265279052da96728c4e855e3bf2bf3a661a57245fda9b0cff74d0314e6d6391175f1064be3ffe7637249b1b3e0f91728243f1ce7b2f
|
7
|
+
data.tar.gz: 632c0ffe2b237905b1b0c0fe8c1dfbea9eb83678e3905eb26a51538d6219a5b75c1ee399fe20c985570999e5acf9574df59730d7acca45b80ce6b06984390f05
|
@@ -1,171 +1,7 @@
|
|
1
1
|
desc 'commit', 'Commit using a story title from Pivotal Tracker'
|
2
2
|
def commit
|
3
|
+
require 'geordi/gitpt'
|
4
|
+
|
3
5
|
Gitpt.new.run
|
4
6
|
end
|
5
7
|
|
6
|
-
class Gitpt
|
7
|
-
include Geordi::Interaction
|
8
|
-
require 'yaml'
|
9
|
-
require 'highline'
|
10
|
-
require 'pivotal-tracker'
|
11
|
-
|
12
|
-
attr_reader :token, :initials, :settings_file, :deprecated_token_file,
|
13
|
-
:highline, :applicable_stories, :memberships
|
14
|
-
|
15
|
-
def initialize
|
16
|
-
@highline = HighLine.new
|
17
|
-
@settings_file = File.join(ENV['HOME'], '.gitpt')
|
18
|
-
@deprecated_token_file = File.join(ENV['HOME'], '.pt_token')
|
19
|
-
load_settings
|
20
|
-
settings_were_invalid = (not settings_valid?)
|
21
|
-
|
22
|
-
hello unless settings_valid?
|
23
|
-
request_settings while not settings_valid?
|
24
|
-
stored if settings_were_invalid
|
25
|
-
|
26
|
-
PivotalTracker::Client.use_ssl = true
|
27
|
-
PivotalTracker::Client.token = token
|
28
|
-
end
|
29
|
-
|
30
|
-
def settings_valid?
|
31
|
-
token and token.size > 10
|
32
|
-
end
|
33
|
-
|
34
|
-
def bold(string)
|
35
|
-
HighLine::BOLD + string + HighLine::RESET
|
36
|
-
end
|
37
|
-
|
38
|
-
def highlight(string)
|
39
|
-
bold HighLine::BLUE + string
|
40
|
-
end
|
41
|
-
|
42
|
-
def hello
|
43
|
-
highline.say HighLine::RESET
|
44
|
-
highline.say "Welcome to #{bold 'gitpt'}.\n\n"
|
45
|
-
end
|
46
|
-
|
47
|
-
def loading(message, &block)
|
48
|
-
print message
|
49
|
-
STDOUT.flush
|
50
|
-
yield
|
51
|
-
print "\r" + ' ' * message.size + "\r" # Remove loading message
|
52
|
-
STDOUT.flush
|
53
|
-
end
|
54
|
-
|
55
|
-
def stored
|
56
|
-
highline.say left(<<-MESSAGE)
|
57
|
-
Thank you. Your settings have been stored at #{highlight @settings_file}
|
58
|
-
You may remove that file for the wizard to reappear.
|
59
|
-
|
60
|
-
----------------------------------------------------
|
61
|
-
|
62
|
-
MESSAGE
|
63
|
-
end
|
64
|
-
|
65
|
-
def request_settings
|
66
|
-
highline.say highlight('Your settings are missing or invalid.')
|
67
|
-
highline.say "Please configure your Pivotal Tracker access.\n\n"
|
68
|
-
token = highline.ask bold("Your API key:") + " "
|
69
|
-
initials = highline.ask bold("Your PT initials") + " (optional, used for highlighting your stories): "
|
70
|
-
highline.say "\n"
|
71
|
-
|
72
|
-
settings = { :token => token, :initials => initials }
|
73
|
-
File.open settings_file, 'w' do |file|
|
74
|
-
file.write settings.to_yaml
|
75
|
-
end
|
76
|
-
load_settings
|
77
|
-
end
|
78
|
-
|
79
|
-
def load_settings
|
80
|
-
if File.exists? settings_file
|
81
|
-
settings = YAML.load(File.read settings_file)
|
82
|
-
@initials = settings[:initials]
|
83
|
-
@token = settings[:token]
|
84
|
-
else
|
85
|
-
if File.exists?(deprecated_token_file)
|
86
|
-
highline.say left(<<-MESSAGE)
|
87
|
-
#{HighLine::YELLOW}You are still using #{highlight(deprecated_token_file) + HighLine::YELLOW} which will be deprecated in a future version.
|
88
|
-
Please migrate your settings to ~/.gitpt or remove #{deprecated_token_file} for the wizard to cast magic.
|
89
|
-
MESSAGE
|
90
|
-
@token = File.read(deprecated_token_file)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def load_projects
|
96
|
-
project_id_filename = '.pt_project_id'
|
97
|
-
if File.exists?(project_id_filename)
|
98
|
-
project_ids = File.read('.pt_project_id').split(/[\s]+/).map(&:to_i)
|
99
|
-
end
|
100
|
-
|
101
|
-
unless project_ids and project_ids.size > 0
|
102
|
-
highline.say left(<<-MESSAGE)
|
103
|
-
Sorry, I could not find a project ID in #{highlight project_id_filename} :(
|
104
|
-
|
105
|
-
Please put at least one Pivotal Tracker project id into #{project_id_filename} in this directory.
|
106
|
-
You may add multiple IDs, separated using white space.
|
107
|
-
MESSAGE
|
108
|
-
exit 1
|
109
|
-
end
|
110
|
-
|
111
|
-
loading 'Connecting to Pivotal Tracker...' do
|
112
|
-
projects = project_ids.collect do |project_id|
|
113
|
-
PivotalTracker::Project.find(project_id)
|
114
|
-
end
|
115
|
-
|
116
|
-
@memberships = projects.collect(&:memberships).map(&:all).flatten
|
117
|
-
|
118
|
-
@applicable_stories = projects.collect do |project|
|
119
|
-
project.stories.all(:state => 'started,finished,rejected')
|
120
|
-
end.flatten
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def choose_story
|
125
|
-
selected_story = nil
|
126
|
-
|
127
|
-
highline.choose do |menu|
|
128
|
-
menu.header = "Choose a story"
|
129
|
-
applicable_stories.each do |story|
|
130
|
-
owner_name = story.owned_by
|
131
|
-
owner = if owner_name
|
132
|
-
owners = memberships.select{|member| member.name == owner_name}
|
133
|
-
owners.first ? owners.first.initials : '?'
|
134
|
-
else
|
135
|
-
'?'
|
136
|
-
end
|
137
|
-
|
138
|
-
state = story.current_state
|
139
|
-
if state == 'started'
|
140
|
-
state = HighLine::GREEN + state + HighLine::RESET
|
141
|
-
elsif state != 'finished'
|
142
|
-
state = HighLine::RED + state + HighLine::RESET
|
143
|
-
end
|
144
|
-
state += HighLine::BOLD if owner == initials
|
145
|
-
|
146
|
-
label = "(#{owner}, #{state}) #{story.name}"
|
147
|
-
label = bold(label) if owner == initials
|
148
|
-
menu.choice(label) { selected_story = story }
|
149
|
-
end
|
150
|
-
menu.hidden ''
|
151
|
-
end
|
152
|
-
|
153
|
-
if selected_story
|
154
|
-
message = highline.ask("\nAdd an optional message")
|
155
|
-
highline.say message
|
156
|
-
|
157
|
-
commit_message = "[##{selected_story.id}] #{selected_story.name}"
|
158
|
-
if message.strip != ''
|
159
|
-
commit_message << ' - '<< message.strip
|
160
|
-
end
|
161
|
-
|
162
|
-
exec('git', 'commit', '-m', commit_message)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def run
|
167
|
-
load_projects
|
168
|
-
choose_story
|
169
|
-
end
|
170
|
-
|
171
|
-
end
|
@@ -2,14 +2,13 @@ desc 'deploy', 'Guided deployment'
|
|
2
2
|
def deploy
|
3
3
|
ENV['PAGER'] = 'cat'
|
4
4
|
|
5
|
-
master_branch = prompt
|
6
|
-
production_branch = prompt
|
7
|
-
production_stage = prompt
|
5
|
+
master_branch = prompt 'master branch:', 'master'
|
6
|
+
production_branch = prompt 'production branch:', 'production'
|
7
|
+
production_stage = prompt 'production capistrano stage:', 'production'
|
8
8
|
|
9
9
|
announce "Checking if your #{master_branch} is up to date"
|
10
|
-
|
11
|
-
|
12
|
-
changes_size = call_or_fail('git status -s | wc -l', true)
|
10
|
+
diff_size = `git fetch && git diff #{master_branch} origin/#{master_branch} | wc -l`.strip
|
11
|
+
changes_size = `git status -s | wc -l`.strip
|
13
12
|
|
14
13
|
if diff_size == '0' and changes_size == '0'
|
15
14
|
note 'All good.'
|
@@ -18,48 +17,23 @@ def deploy
|
|
18
17
|
end
|
19
18
|
|
20
19
|
announce "Checking what's on #{production_stage} right now..."
|
21
|
-
|
22
|
-
call_or_fail "git checkout #{production_branch} && git pull"
|
20
|
+
Util.system! "git checkout #{production_branch} && git pull"
|
23
21
|
|
24
22
|
announce "You are about to deploy the following commits from #{master_branch} to #{production_branch}:"
|
23
|
+
Util.system! "git log #{production_branch}..#{master_branch} --oneline"
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
if prompt('Go ahead with the deployment?', 'n').downcase == 'y'
|
29
|
-
puts
|
25
|
+
if prompt('Go ahead with the deployment?', 'n', /y|yes/)
|
30
26
|
capistrano_call = "cap #{production_stage} deploy:migrations"
|
31
27
|
if file_containing?('Gemfile', /capistrano/)
|
32
28
|
capistrano_call = "bundle exec #{capistrano_call}"
|
33
29
|
end
|
34
|
-
call_or_fail("git merge #{master_branch} && git push && #{capistrano_call}")
|
35
|
-
success 'Deployment complete.'
|
36
|
-
else
|
37
|
-
fail 'Deployment cancelled.'
|
38
|
-
end
|
39
30
|
|
40
|
-
|
41
|
-
|
42
|
-
private
|
31
|
+
puts
|
32
|
+
Util.system! "git merge #{master_branch} && git push && #{capistrano_call}"
|
43
33
|
|
44
|
-
|
45
|
-
note_cmd command
|
46
|
-
if return_output
|
47
|
-
result = `#{command}`.to_s.strip
|
48
|
-
$?.success? or fail "Error while calling #{command}: #{$?}"
|
34
|
+
success 'Deployment complete.'
|
49
35
|
else
|
50
|
-
|
51
|
-
puts
|
36
|
+
fail 'Deployment cancelled.'
|
52
37
|
end
|
53
|
-
result
|
54
|
-
end
|
55
38
|
|
56
|
-
def prompt(message, default)
|
57
|
-
print "#{message}"
|
58
|
-
print " [#{default}]" if default
|
59
|
-
print ": "
|
60
|
-
input = $stdin.gets.strip
|
61
|
-
if input.empty? && default
|
62
|
-
input = default
|
63
|
-
end
|
64
|
-
input
|
65
39
|
end
|
@@ -13,11 +13,9 @@ def security_update(step='prepare')
|
|
13
13
|
when 'prepare'
|
14
14
|
announce 'Preparing for security update'
|
15
15
|
warn 'Please read https://makandracards.com/makandra/1587 before applying security updates!'
|
16
|
-
note 'About to
|
17
|
-
|
16
|
+
note 'About to checkout production and pull'
|
17
|
+
prompt('Continue?', 'y', /y|yes/) or fail 'Cancelled.'
|
18
18
|
|
19
|
-
Util.system! 'git checkout master', :show_cmd => true
|
20
|
-
Util.system! 'git pull', :show_cmd => true
|
21
19
|
Util.system! 'git checkout production', :show_cmd => true
|
22
20
|
Util.system! 'git pull', :show_cmd => true
|
23
21
|
|
@@ -34,11 +32,10 @@ def security_update(step='prepare')
|
|
34
32
|
`git status --porcelain`.empty? or fail('There are uncommitted changes.')
|
35
33
|
note 'Working directory clean.'
|
36
34
|
|
37
|
-
|
38
|
-
exit unless $stdin.gets =~ /[yes]+/
|
35
|
+
prompt('Have you successfully run all tests?', 'n', /y|yes/) or fail 'Please run tests first.'
|
39
36
|
|
40
37
|
note 'About to: push production, checkout & pull master, merge production, push master, deploy all stages'
|
41
|
-
|
38
|
+
prompt('Continue?', 'n', /y|yes/) or fail 'Cancelled.'
|
42
39
|
|
43
40
|
Util.system! 'git push', :show_cmd => true
|
44
41
|
Util.system! 'git checkout master', :show_cmd => true
|
@@ -1,84 +1,66 @@
|
|
1
|
-
class ::String
|
2
|
-
def colorize(color_code)
|
3
|
-
"\e[#{color_code}m#{self}\e[0m"
|
4
|
-
end
|
5
|
-
|
6
|
-
def red() colorize(31) end
|
7
|
-
def pink() colorize(35) end
|
8
|
-
def green() colorize(32) end
|
9
|
-
end
|
10
|
-
|
11
1
|
desc 'setup-vnc', 'Setup VNC for running Selenium tests there'
|
12
2
|
def setup_vnc
|
13
3
|
`clear`
|
14
4
|
|
15
|
-
|
16
|
-
|
17
|
-
|
5
|
+
note 'This script will help you install a VNC server and a VNC viewer.'
|
6
|
+
puts
|
7
|
+
puts strip_heredoc <<-TEXT
|
18
8
|
With those you will be able to use our cucumber script without being
|
19
|
-
disturbed by focus-stealing
|
20
|
-
inside a VNC session.
|
21
|
-
vnc_show".pink}.
|
9
|
+
disturbed by focus-stealing Selenium windows. Instead, they will open
|
10
|
+
inside a VNC session.
|
22
11
|
|
23
|
-
|
12
|
+
You can still inspect everything with:
|
24
13
|
TEXT
|
14
|
+
note_cmd 'geordi vnc-show'
|
15
|
+
puts
|
16
|
+
note 'Please open a second shell to execute instructions.'
|
17
|
+
prompt 'Continue ...'
|
25
18
|
|
26
19
|
announce 'Setup VNC server'
|
27
20
|
|
28
|
-
|
21
|
+
vnc_server_installed = system('which vncserver > /dev/null 2>&1')
|
22
|
+
if vnc_server_installed
|
29
23
|
success 'It appears you already have a VNC server installed. Good job!'
|
30
24
|
else
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
instruct <<-TEXT
|
36
|
-
We will now set a password for your VNC server.
|
25
|
+
puts 'Please run:'
|
26
|
+
note_cmd 'sudo apt-get install vnc4server'
|
27
|
+
prompt 'Continue ...'
|
37
28
|
|
29
|
+
puts
|
30
|
+
note 'We will now set a password for your VNC server.'
|
31
|
+
puts strip_heredoc <<-TEXT
|
38
32
|
When running our cucumber script, you will not actually need this
|
39
33
|
password, and there is no security risk. However, if you start a vncserver
|
40
34
|
without our cucumber script, a user with your password can connect to
|
41
35
|
your machine.
|
42
36
|
|
43
|
-
Please run #{'vncserver :20'.pink} and #{'enter a secure password'.red}.
|
44
|
-
TEXT
|
45
|
-
|
46
|
-
instruct <<-TEXT
|
47
|
-
Now stop the server again.
|
48
|
-
Please run #{'vncserver -kill :20'.pink}.
|
49
37
|
TEXT
|
38
|
+
puts 'Please run:'
|
39
|
+
note_cmd 'vncserver :20'
|
40
|
+
warn 'Enter a secure password!'
|
41
|
+
prompt 'Continue ...'
|
42
|
+
|
43
|
+
puts 'Now stop the server again. Please run:'
|
44
|
+
note_cmd 'vncserver -kill :20'
|
45
|
+
prompt 'Continue ...'
|
50
46
|
end
|
51
47
|
|
52
48
|
announce 'Setup VNC viewer'
|
53
49
|
|
54
|
-
|
50
|
+
vnc_viewer_installed = system('which vncviewer > /dev/null 2>&1')
|
51
|
+
if vnc_viewer_installed
|
55
52
|
success 'It appears you already have a VNC viewer installed. Good job!'
|
56
53
|
else
|
57
|
-
|
58
|
-
|
59
|
-
|
54
|
+
puts 'Please run:'
|
55
|
+
note_cmd 'sudo apt-get install xtightvncviewer'
|
56
|
+
prompt 'Continue ...'
|
60
57
|
end
|
61
58
|
|
62
|
-
|
59
|
+
puts
|
60
|
+
puts strip_heredoc <<-TEXT
|
63
61
|
All done. Our cucumber script will now automatically run Selenium features
|
64
62
|
in VNC.
|
65
|
-
#{"Happy cuking!".green}
|
66
63
|
TEXT
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def instruct(text, wait = true)
|
73
|
-
text =~ /^( *)./
|
74
|
-
level = $1 ? $1.size : 0
|
75
|
-
text.gsub!(/^ {#{level}}/, '')
|
76
|
-
puts text
|
77
|
-
|
78
|
-
wait('[ENTER]') if wait
|
79
|
-
end
|
80
|
-
|
81
|
-
def installed?(app)
|
82
|
-
`which #{app}`
|
83
|
-
$?.success?
|
65
|
+
success 'Happy cuking!'
|
84
66
|
end
|
@@ -70,7 +70,7 @@ module Geordi
|
|
70
70
|
unless FirefoxForSelenium.binary(@version).exist?
|
71
71
|
note "Firefox #{@version} not found."
|
72
72
|
|
73
|
-
puts
|
73
|
+
puts strip_heredoc(<<-INSTRUCTIONS)
|
74
74
|
Install it with
|
75
75
|
geordi setup_firefox_for_selenium #{@version}
|
76
76
|
|
@@ -137,7 +137,7 @@ module Geordi
|
|
137
137
|
def say_hello
|
138
138
|
execute_command('clear')
|
139
139
|
|
140
|
-
puts
|
140
|
+
puts strip_heredoc(<<-HELLO)
|
141
141
|
Whenever Firefox updates, Selenium breaks. This is annoying. This
|
142
142
|
script will help you create an unchanging version of Firefox for your
|
143
143
|
Selenium tests.
|
@@ -154,30 +154,27 @@ module Geordi
|
|
154
154
|
- It will automatically be used for your Selenium scenarios if you run
|
155
155
|
your Cucumber using the cuc binary from the geordi gem.
|
156
156
|
- It will live in #{path}
|
157
|
-
|
158
157
|
HELLO
|
159
158
|
|
160
|
-
|
159
|
+
prompt "Press ENTER when you're ready to begin."
|
161
160
|
end
|
162
161
|
|
163
162
|
def check_if_run_before
|
164
163
|
if original_binary.exist?
|
165
164
|
note 'This version seems to be already installed.'
|
166
|
-
|
167
|
-
wait 'Press ENTER to continue anyway or press CTRL+C to abort.'
|
165
|
+
prompt 'Press ENTER to continue anyway or press CTRL+C to abort.'
|
168
166
|
end
|
169
167
|
end
|
170
168
|
|
171
169
|
def download_firefox
|
172
170
|
path.mkpath
|
173
171
|
|
174
|
-
puts
|
172
|
+
puts strip_heredoc(<<-INSTRUCTION)
|
175
173
|
Please download an old version of Firefox from: #{download_url}
|
176
174
|
Unpack it with: tar xvjf firefox-#{@version}.tar.bz2 -C #{path} --strip-components=1
|
177
175
|
Now #{path.join('firefox')} should be the firefox binary, not a directory.
|
178
|
-
|
179
176
|
INSTRUCTION
|
180
|
-
|
177
|
+
prompt "Press ENTER when you're done."
|
181
178
|
|
182
179
|
File.file?(binary) or raise "Could not find #{binary}"
|
183
180
|
end
|
@@ -195,7 +192,7 @@ module Geordi
|
|
195
192
|
execute_command("mv #{binary} #{original_binary}")
|
196
193
|
execute_command("mv #{binary}-bin #{original_binary}-bin")
|
197
194
|
patched_binary = Tempfile.new('firefox')
|
198
|
-
patched_binary.write
|
195
|
+
patched_binary.write strip_heredoc(<<-PATCH)
|
199
196
|
#!/usr/bin/env ruby
|
200
197
|
exec('#{original_binary}', '-no-remote', '-P', '#{FIREFOX_FOR_SELENIUM_PROFILE_NAME}', *ARGV)
|
201
198
|
PATCH
|
@@ -206,7 +203,7 @@ module Geordi
|
|
206
203
|
end
|
207
204
|
|
208
205
|
def configure_old_firefox
|
209
|
-
puts
|
206
|
+
puts strip_heredoc(<<-INSTRUCTION)
|
210
207
|
You will now have to do some manual configuration.
|
211
208
|
|
212
209
|
This script will open the patched copy of Firefox when you press ENTER.
|
@@ -218,18 +215,17 @@ module Geordi
|
|
218
215
|
Firefox profile
|
219
216
|
- Disable all automatic updates under Edit / Preferences / Advanced /
|
220
217
|
Update (do this quickly or Firefox will already have updated)
|
221
|
-
|
222
218
|
INSTRUCTION
|
223
219
|
|
224
|
-
|
220
|
+
prompt 'Open the patched copy of Firefox with ENTER.'
|
225
221
|
run_firefox_for_selenium
|
226
222
|
end
|
227
223
|
|
228
224
|
def kkthxbb
|
229
225
|
success "Congratulations, you're done!"
|
230
226
|
|
231
|
-
puts
|
232
|
-
|
227
|
+
puts
|
228
|
+
puts strip_heredoc(<<-INSTRUCTION)
|
233
229
|
Your patched copy of Firefox will be used when you run Cucumber using
|
234
230
|
the cucumber script that comes with the geordi gem. If you prefer to run
|
235
231
|
Cucumber on your own, you must call it like this:
|
data/lib/geordi/gitpt.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
class Gitpt
|
2
|
+
include Geordi::Interaction
|
3
|
+
require 'yaml'
|
4
|
+
require 'highline'
|
5
|
+
require 'pivotal-tracker'
|
6
|
+
|
7
|
+
attr_reader :token, :initials, :settings_file, :deprecated_token_file,
|
8
|
+
:highline, :applicable_stories, :memberships
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@highline = HighLine.new
|
12
|
+
@settings_file = File.join(ENV['HOME'], '.gitpt')
|
13
|
+
@deprecated_token_file = File.join(ENV['HOME'], '.pt_token')
|
14
|
+
load_settings
|
15
|
+
settings_were_invalid = (not settings_valid?)
|
16
|
+
|
17
|
+
hello unless settings_valid?
|
18
|
+
request_settings while not settings_valid?
|
19
|
+
stored if settings_were_invalid
|
20
|
+
|
21
|
+
PivotalTracker::Client.use_ssl = true
|
22
|
+
PivotalTracker::Client.token = token
|
23
|
+
end
|
24
|
+
|
25
|
+
def settings_valid?
|
26
|
+
token and token.size > 10
|
27
|
+
end
|
28
|
+
|
29
|
+
def bold(string)
|
30
|
+
HighLine::BOLD + string + HighLine::RESET
|
31
|
+
end
|
32
|
+
|
33
|
+
def highlight(string)
|
34
|
+
bold HighLine::BLUE + string
|
35
|
+
end
|
36
|
+
|
37
|
+
def hello
|
38
|
+
highline.say HighLine::RESET
|
39
|
+
highline.say "Welcome to #{bold 'gitpt'}.\n\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
def loading(message, &block)
|
43
|
+
print message
|
44
|
+
STDOUT.flush
|
45
|
+
yield
|
46
|
+
print "\r" + ' ' * message.size + "\r" # Remove loading message
|
47
|
+
STDOUT.flush
|
48
|
+
end
|
49
|
+
|
50
|
+
def stored
|
51
|
+
highline.say strip_heredoc(<<-MESSAGE)
|
52
|
+
Thank you. Your settings have been stored at #{highlight @settings_file}
|
53
|
+
You may remove that file for the wizard to reappear.
|
54
|
+
|
55
|
+
----------------------------------------------------
|
56
|
+
|
57
|
+
MESSAGE
|
58
|
+
end
|
59
|
+
|
60
|
+
def request_settings
|
61
|
+
highline.say highlight('Your settings are missing or invalid.')
|
62
|
+
highline.say "Please configure your Pivotal Tracker access.\n\n"
|
63
|
+
token = highline.ask bold("Your API key:") + " "
|
64
|
+
initials = highline.ask bold("Your PT initials") + " (optional, used for highlighting your stories): "
|
65
|
+
highline.say "\n"
|
66
|
+
|
67
|
+
settings = { :token => token, :initials => initials }
|
68
|
+
File.open settings_file, 'w' do |file|
|
69
|
+
file.write settings.to_yaml
|
70
|
+
end
|
71
|
+
load_settings
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_settings
|
75
|
+
if File.exists? settings_file
|
76
|
+
settings = YAML.load(File.read settings_file)
|
77
|
+
@initials = settings[:initials]
|
78
|
+
@token = settings[:token]
|
79
|
+
else
|
80
|
+
if File.exists?(deprecated_token_file)
|
81
|
+
highline.say strip_heredoc(<<-MESSAGE)
|
82
|
+
#{HighLine::YELLOW}You are still using #{highlight(deprecated_token_file) + HighLine::YELLOW} which will be deprecated in a future version.
|
83
|
+
Please migrate your settings to ~/.gitpt or remove #{deprecated_token_file} for the wizard to cast magic.
|
84
|
+
MESSAGE
|
85
|
+
@token = File.read(deprecated_token_file)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def load_projects
|
91
|
+
project_id_filename = '.pt_project_id'
|
92
|
+
if File.exists?(project_id_filename)
|
93
|
+
project_ids = File.read('.pt_project_id').split(/[\s]+/).map(&:to_i)
|
94
|
+
end
|
95
|
+
|
96
|
+
unless project_ids and project_ids.size > 0
|
97
|
+
warn "Sorry, I could not find a project ID in #{project_id_filename} :("
|
98
|
+
puts
|
99
|
+
|
100
|
+
puts "Please put at least one Pivotal Tracker project id into #{project_id_filename} in this directory."
|
101
|
+
puts 'You may add multiple IDs, separated using white space.'
|
102
|
+
exit 1
|
103
|
+
end
|
104
|
+
|
105
|
+
loading 'Connecting to Pivotal Tracker...' do
|
106
|
+
projects = project_ids.collect do |project_id|
|
107
|
+
PivotalTracker::Project.find(project_id)
|
108
|
+
end
|
109
|
+
|
110
|
+
@memberships = projects.collect(&:memberships).map(&:all).flatten
|
111
|
+
|
112
|
+
@applicable_stories = projects.collect do |project|
|
113
|
+
project.stories.all(:state => 'started,finished,rejected')
|
114
|
+
end.flatten
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def choose_story
|
119
|
+
selected_story = nil
|
120
|
+
|
121
|
+
highline.choose do |menu|
|
122
|
+
menu.header = "Choose a story"
|
123
|
+
applicable_stories.each do |story|
|
124
|
+
owner_name = story.owned_by
|
125
|
+
owner = if owner_name
|
126
|
+
owners = memberships.select{|member| member.name == owner_name}
|
127
|
+
owners.first ? owners.first.initials : '?'
|
128
|
+
else
|
129
|
+
'?'
|
130
|
+
end
|
131
|
+
|
132
|
+
state = story.current_state
|
133
|
+
if state == 'started'
|
134
|
+
state = HighLine::GREEN + state + HighLine::RESET
|
135
|
+
elsif state != 'finished'
|
136
|
+
state = HighLine::RED + state + HighLine::RESET
|
137
|
+
end
|
138
|
+
state += HighLine::BOLD if owner == initials
|
139
|
+
|
140
|
+
label = "(#{owner}, #{state}) #{story.name}"
|
141
|
+
label = bold(label) if owner == initials
|
142
|
+
menu.choice(label) { selected_story = story }
|
143
|
+
end
|
144
|
+
menu.hidden ''
|
145
|
+
end
|
146
|
+
|
147
|
+
if selected_story
|
148
|
+
message = highline.ask("\nAdd an optional message")
|
149
|
+
highline.say message
|
150
|
+
|
151
|
+
commit_message = "[##{selected_story.id}] #{selected_story.name}"
|
152
|
+
if message.strip != ''
|
153
|
+
commit_message << ' - '<< message.strip
|
154
|
+
end
|
155
|
+
|
156
|
+
exec('git', 'commit', '-m', commit_message)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def run
|
161
|
+
load_projects
|
162
|
+
choose_story
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
data/lib/geordi/interaction.rb
CHANGED
@@ -31,17 +31,25 @@ module Geordi
|
|
31
31
|
puts "\e[32m#{message}\e[0m" # green
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
message = "#{text}"
|
36
|
-
puts "\e[36m#{message}\e[0m" # cyan
|
37
|
-
$stdin.gets
|
38
|
-
end
|
39
|
-
|
40
|
-
def left(string)
|
34
|
+
def strip_heredoc(string)
|
41
35
|
leading_whitespace = (string.match(/\A( +)[^ ]+/) || [])[1]
|
42
36
|
string.gsub! /^#{leading_whitespace}/, '' if leading_whitespace
|
43
37
|
string
|
44
38
|
end
|
45
39
|
|
40
|
+
# Returns the user's input.
|
41
|
+
# If agreement_regex is given, returns whether the input matches the regex.
|
42
|
+
def prompt(text, default = nil, agreement_regex = nil)
|
43
|
+
message = "#{text} "
|
44
|
+
message << "[#{default}] " if default
|
45
|
+
|
46
|
+
puts
|
47
|
+
print "\e[36m#{message}\e[0m" # cyan
|
48
|
+
input = $stdin.gets.strip
|
49
|
+
input = default if input.empty? && default
|
50
|
+
|
51
|
+
agreement_regex ? !!(input =~ agreement_regex) : input
|
52
|
+
end
|
53
|
+
|
46
54
|
end
|
47
55
|
end
|
data/lib/geordi/util.rb
CHANGED
@@ -11,18 +11,21 @@ module Geordi
|
|
11
11
|
# Thus, we have this handy method here.
|
12
12
|
def installing_missing_gems(&block)
|
13
13
|
yield
|
14
|
-
rescue LoadError =>
|
15
|
-
|
14
|
+
rescue LoadError => error
|
15
|
+
error.message =~ /-- (\S+)\Z/
|
16
|
+
$1 or raise # could not extract a gem name from the error message, re-raise the error
|
17
|
+
|
18
|
+
gem_name = $1.strip
|
16
19
|
install_command = 'gem install ' + gem_name
|
17
20
|
|
18
21
|
# install missing gem
|
19
22
|
warn 'Probably missing gem: ' + gem_name
|
20
|
-
|
23
|
+
prompt('Install it now?', 'y', /y|yes/) or fail 'Missing Gems.'
|
21
24
|
system! install_command, :show_cmd => true
|
22
25
|
|
23
26
|
# retry
|
24
27
|
Gem.clear_paths
|
25
|
-
note '
|
28
|
+
note 'Retrying ...'
|
26
29
|
require gem_name
|
27
30
|
retry
|
28
31
|
end
|
data/lib/geordi/version.rb
CHANGED
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geordi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henning Koch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.18.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.18.0
|
27
27
|
description: Collection of command line tools we use in our daily work with Ruby,
|
@@ -56,8 +56,8 @@ executables:
|
|
56
56
|
extensions: []
|
57
57
|
extra_rdoc_files: []
|
58
58
|
files:
|
59
|
-
- .gitignore
|
60
|
-
- .ruby-version
|
59
|
+
- ".gitignore"
|
60
|
+
- ".ruby-version"
|
61
61
|
- Gemfile
|
62
62
|
- LICENSE
|
63
63
|
- README.md
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- lib/geordi/cucumber.rb
|
125
125
|
- lib/geordi/dump_loader.rb
|
126
126
|
- lib/geordi/firefox_for_selenium.rb
|
127
|
+
- lib/geordi/gitpt.rb
|
127
128
|
- lib/geordi/interaction.rb
|
128
129
|
- lib/geordi/remote.rb
|
129
130
|
- lib/geordi/run_tests.rb
|
@@ -133,7 +134,7 @@ homepage: http://makandra.com
|
|
133
134
|
licenses:
|
134
135
|
- MIT
|
135
136
|
metadata: {}
|
136
|
-
post_install_message:
|
137
|
+
post_install_message: "\n ********************************************\n\n geordi
|
137
138
|
1.0 moves most of the scripts to\n the `geordi` binary. Run `geordi` and\n `geordi
|
138
139
|
help <cmd>` for further information.\n\n Tip: Create an alias for geordi for
|
139
140
|
quick \n access. Add this to your ~/.bashrc:\n\n alias g=\"geordi\"\n\n
|
@@ -143,17 +144,17 @@ require_paths:
|
|
143
144
|
- lib
|
144
145
|
required_ruby_version: !ruby/object:Gem::Requirement
|
145
146
|
requirements:
|
146
|
-
- -
|
147
|
+
- - ">="
|
147
148
|
- !ruby/object:Gem::Version
|
148
149
|
version: '0'
|
149
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
151
|
requirements:
|
151
|
-
- -
|
152
|
+
- - ">="
|
152
153
|
- !ruby/object:Gem::Version
|
153
154
|
version: '0'
|
154
155
|
requirements: []
|
155
156
|
rubyforge_project: geordi
|
156
|
-
rubygems_version: 2.
|
157
|
+
rubygems_version: 2.4.3
|
157
158
|
signing_key:
|
158
159
|
specification_version: 4
|
159
160
|
summary: Collection of command line tools we use in our daily work with Ruby, Rails
|