geordi 3.0.2 → 4.0.1

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +44 -6
  5. data/Gemfile.lock +1 -1
  6. data/README.md +138 -118
  7. data/Rakefile +18 -8
  8. data/geordi.gemspec +1 -0
  9. data/lib/geordi/COMMAND_TEMPLATE +3 -1
  10. data/lib/geordi/commands/chromedriver_update.rb +2 -2
  11. data/lib/geordi/commands/commit.rb +1 -6
  12. data/lib/geordi/commands/console.rb +9 -4
  13. data/lib/geordi/commands/create_databases.rb +2 -1
  14. data/lib/geordi/commands/cucumber.rb +15 -10
  15. data/lib/geordi/commands/delete_dumps.rb +0 -1
  16. data/lib/geordi/commands/deploy.rb +11 -11
  17. data/lib/geordi/commands/drop_databases.rb +0 -6
  18. data/lib/geordi/commands/dump.rb +9 -18
  19. data/lib/geordi/commands/firefox.rb +2 -5
  20. data/lib/geordi/commands/migrate.rb +1 -1
  21. data/lib/geordi/commands/rake.rb +3 -1
  22. data/lib/geordi/commands/rspec.rb +5 -9
  23. data/lib/geordi/commands/security_update.rb +65 -9
  24. data/lib/geordi/commands/server.rb +1 -1
  25. data/lib/geordi/commands/setup.rb +2 -11
  26. data/lib/geordi/commands/shell.rb +7 -4
  27. data/lib/geordi/commands/unit.rb +1 -1
  28. data/lib/geordi/commands/update.rb +0 -11
  29. data/lib/geordi/commands/vnc.rb +1 -3
  30. data/lib/geordi/commands/with_rake.rb +1 -1
  31. data/lib/geordi/cucumber.rb +6 -4
  32. data/lib/geordi/dump_loader.rb +3 -1
  33. data/lib/geordi/gitpt.rb +9 -51
  34. data/lib/geordi/remote.rb +14 -2
  35. data/lib/geordi/settings.rb +155 -0
  36. data/lib/geordi/util.rb +12 -4
  37. data/lib/geordi/version.rb +1 -1
  38. metadata +7 -33
  39. data/exe/cap-all +0 -4
  40. data/exe/console-for +0 -4
  41. data/exe/cuc +0 -4
  42. data/exe/cuc-show +0 -4
  43. data/exe/cuc-vnc-setup +0 -4
  44. data/exe/deploy-to-production +0 -4
  45. data/exe/dump-for +0 -8
  46. data/exe/gitpt +0 -4
  47. data/exe/load-dump +0 -4
  48. data/exe/migrate-all +0 -4
  49. data/exe/rs +0 -4
  50. data/exe/run_tests +0 -4
  51. data/exe/shell-for +0 -4
  52. data/exe/tests +0 -4
  53. data/lib/geordi/commands/eurest.rb +0 -4
@@ -3,7 +3,7 @@ desc 'server [PORT]', 'Start a development server'
3
3
  option :port, aliases: '-p', default: '3000',
4
4
  desc: 'Choose a port'
5
5
  option :public, aliases: '-P', type: :boolean,
6
- desc: 'Make the server accessible in the local network'
6
+ desc: 'Make the server accessible from the local network'
7
7
 
8
8
  def server(port = nil)
9
9
  invoke_cmd 'bundle_install'
@@ -6,17 +6,8 @@ Check out a repository and cd into its directory. Then let `setup` do the tiring
6
6
  work: run `bundle install`, create `database.yml`, create databases, migrate
7
7
  (all if applicable).
8
8
 
9
- If a local bin/setup file is found, Geordi skips these steps runs bin/setup
10
- for setup instead.
11
-
12
- After setting up, loads a remote database dump into the development db when
13
- called with the `--dump` option:
14
-
15
- geordi setup -d staging
16
-
17
- After setting up, runs all tests when called with the `--test` option:
18
-
19
- geordi setup -t
9
+ If a local bin/setup file is found, Geordi skips its routine and runs bin/setup
10
+ instead.
20
11
  LONGDESC
21
12
 
22
13
  option :dump, type: :string, aliases: '-d', banner: 'TARGET',
@@ -2,18 +2,21 @@ desc 'shell TARGET', 'Open a shell on a Capistrano deploy target'
2
2
  long_desc <<-LONGDESC
3
3
  Example: `geordi shell production`
4
4
 
5
- Lets you select the server to connect to when called with `--select-server`:
6
-
7
- geordi shell production -s
5
+ Selecting the server: `geordi shell staging -s` shows a menu with all available
6
+ servers. When passed a number, directly connects to the selected server.
8
7
  LONGDESC
9
8
 
10
- option :select_server, default: false, type: :boolean, aliases: '-s'
9
+ # This option is duplicated in console.rb
10
+ option :select_server, type: :string, aliases: '-s', banner: '[SERVER_NUMBER]',
11
+ desc: 'Select a server to connect to'
11
12
 
12
13
  # This method has a triple 'l' because :shell is a Thor reserved word. However,
13
14
  # it can still be called with `geordi shell` :)
14
15
  def shelll(target, *_args)
15
16
  require 'geordi/remote'
16
17
 
18
+ invoke_cmd 'bundle_install'
19
+
17
20
  Interaction.announce 'Opening a shell on ' + target
18
21
  Geordi::Remote.new(target).shell(options)
19
22
  end
@@ -5,7 +5,7 @@ def unit
5
5
  invoke_cmd 'yarn_install'
6
6
 
7
7
  Interaction.announce 'Running Test::Unit'
8
- Util.system! 'bundle exec rake test'
8
+ Util.system! Util.binstub('rake'), 'test'
9
9
  else
10
10
  Interaction.note 'Test::Unit not employed.'
11
11
  end
@@ -3,17 +3,6 @@ long_desc <<-LONGDESC
3
3
  Example: `geordi update`
4
4
 
5
5
  Performs: `git pull`, `bundle install` (if necessary) and migrates (if applicable).
6
-
7
- After updating, loads a dump into the development db when called with the
8
- `--dump` option:
9
-
10
- geordi update -d staging
11
-
12
- After updating, runs all tests when called with the `--test` option:
13
-
14
- geordi update -t
15
-
16
- See `geordi help update` for details.
17
6
  LONGDESC
18
7
 
19
8
  option :dump, type: :string, aliases: '-d', banner: 'TARGET',
@@ -4,11 +4,9 @@ Example: `geordi vnc` or `geordi vnc --setup`
4
4
 
5
5
  Launch a VNC session to the hidden screen where `geordi cucumber` runs Selenium
6
6
  tests.
7
-
8
- When called with `--setup`, will guide through the setup of VNC.
9
7
  LONGDESC
10
8
 
11
- option :setup, type: :boolean
9
+ option :setup, type: :boolean, desc: 'Guide through the setup of VNC'
12
10
 
13
11
  def vnc
14
12
  if options.setup
@@ -5,7 +5,7 @@ def with_rake
5
5
  invoke_cmd 'yarn_install'
6
6
 
7
7
  Interaction.announce 'Running tests with `rake`'
8
- Util.system! 'rake'
8
+ Util.system! Util.binstub('rake')
9
9
  else
10
10
  Interaction.note '`rake` does not run tests.'
11
11
  :did_not_perform
@@ -5,6 +5,7 @@ require 'tempfile'
5
5
  # version of Geordi.
6
6
  require File.expand_path('interaction', __dir__)
7
7
  require File.expand_path('firefox_for_selenium', __dir__)
8
+ require File.expand_path('settings', __dir__)
8
9
 
9
10
  module Geordi
10
11
  class Cucumber
@@ -16,10 +17,11 @@ module Geordi
16
17
 
17
18
  def run(files, cucumber_options, options = {})
18
19
  self.argv = files + cucumber_options.map { |option| option.split('=') }.flatten
20
+ self.settings = Geordi::Settings.new
19
21
 
20
22
  consolidate_rerun_txt_files
21
23
  show_features_to_run
22
- setup_vnc
24
+ setup_vnc if settings.use_vnc?
23
25
 
24
26
  command = use_parallel_tests?(options) ? parallel_execution_command : serial_execution_command
25
27
  Interaction.note_cmd(command) if options[:verbose]
@@ -65,14 +67,14 @@ module Geordi
65
67
 
66
68
  private
67
69
 
68
- attr_accessor :argv
70
+ attr_accessor :argv, :settings
69
71
 
70
72
  def serial_execution_command
71
73
  format_args = []
72
74
  unless argv.include?('--format') || argv.include?('-f')
73
75
  format_args = spinner_available? ? ['--format', 'CucumberSpinner::CuriousProgressBarFormatter'] : ['--format', 'progress']
74
76
  end
75
- [use_firefox_for_selenium, 'b', 'cucumber', format_args, escape_shell_args(argv)].flatten.compact.join(' ')
77
+ [use_firefox_for_selenium, Util.binstub('cucumber'), format_args, escape_shell_args(argv)].flatten.compact.join(' ')
76
78
  end
77
79
 
78
80
  def parallel_execution_command
@@ -85,7 +87,7 @@ module Geordi
85
87
 
86
88
  [
87
89
  use_firefox_for_selenium,
88
- 'b parallel_test -t ' + type_arg,
90
+ 'bundle exec parallel_test -t ' + type_arg,
89
91
  %(-o '#{command_line_options.join(' ')} --tags "#{not_tag('@solo')}"'),
90
92
  "-- #{features.join(' ')}",
91
93
  ].compact.join(' ')
@@ -13,7 +13,9 @@ module Geordi
13
13
  def development_database_config
14
14
  require 'yaml'
15
15
 
16
- @config ||= YAML.safe_load(ERB.new(File.read('config/database.yml')).result)
16
+ evaluated_config_file = ERB.new(File.read('config/database.yml')).result
17
+ # Allow aliases and a special set of classes like symbols and time objects
18
+ @config ||= YAML.safe_load(evaluated_config_file, [Symbol, Time], [], true)
17
19
  @config['development']
18
20
  end
19
21
  alias_method :config, :development_database_config
@@ -3,12 +3,14 @@ class Gitpt
3
3
  require 'highline'
4
4
  require 'tracker_api'
5
5
 
6
- SETTINGS_FILE_NAME = '.gitpt'.freeze
7
- PROJECT_IDS_FILE_NAME = '.pt_project_id'.freeze
6
+ # This require-style is to prevent Ruby from loading files of a different
7
+ # version of Geordi.
8
+ require File.expand_path('settings', __dir__)
8
9
 
9
10
  def initialize
10
11
  self.highline = HighLine.new
11
- self.client = build_client(read_settings)
12
+ self.settings = Geordi::Settings.new
13
+ self.client = build_client
12
14
  end
13
15
 
14
16
  def run(git_args)
@@ -24,57 +26,17 @@ No staged changes. Will create an empty commit.
24
26
 
25
27
  private
26
28
 
27
- attr_accessor :highline, :client
29
+ attr_accessor :highline, :client, :settings
28
30
 
29
- def read_settings
30
- file_path = File.join(ENV['HOME'], SETTINGS_FILE_NAME)
31
-
32
- unless File.exist?(file_path)
33
- highline.say HighLine::RESET
34
- highline.say "Welcome to #{bold 'gitpt'}.\n\n"
35
-
36
- highline.say highlight('Your settings are missing or invalid.')
37
- highline.say "Please configure your Pivotal Tracker access.\n\n"
38
- token = highline.ask bold('Your API key:') + ' '
39
- highline.say "\n"
40
-
41
- settings = { token: token }
42
- File.open(file_path, 'w') do |file|
43
- file.write settings.to_yaml
44
- end
45
- end
46
-
47
- YAML.load_file(file_path)
48
- end
49
-
50
- def build_client(settings)
51
- TrackerApi::Client.new(token: settings.fetch(:token))
31
+ def build_client
32
+ TrackerApi::Client.new(token: settings.pivotal_tracker_api_key)
52
33
  end
53
34
 
54
35
  def load_projects
55
- project_ids = read_project_ids
36
+ project_ids = settings.pivotal_tracker_project_ids
56
37
  project_ids.collect { |project_id| client.project(project_id) }
57
38
  end
58
39
 
59
- def read_project_ids
60
- file_path = PROJECT_IDS_FILE_NAME
61
-
62
- if File.exist?(file_path)
63
- project_ids = File.read('.pt_project_id').split(/[\s]+/).map(&:to_i)
64
- end
65
-
66
- if project_ids && (project_ids.size > 0)
67
- project_ids
68
- else
69
- Geordi::Interaction.warn "Sorry, I could not find a project ID in #{file_path} :("
70
- puts
71
-
72
- puts "Please put at least one Pivotal Tracker project id into #{file_path} in this directory."
73
- puts 'You may add multiple IDs, separated using white space.'
74
- exit 1
75
- end
76
- end
77
-
78
40
  def applicable_stories
79
41
  projects = load_projects
80
42
  projects.collect do |project|
@@ -134,8 +96,4 @@ No staged changes. Will create an empty commit.
134
96
  HighLine::BOLD + string + HighLine::RESET
135
97
  end
136
98
 
137
- def highlight(string)
138
- bold HighLine::BLUE + string
139
- end
140
-
141
99
  end
@@ -34,7 +34,6 @@ module Geordi
34
34
  # Generate dump on the server
35
35
  shell options.merge({
36
36
  remote_command: "dumple #{@config.env} --for_download",
37
- select_server: nil, # Dump must be generated on the primary server
38
37
  })
39
38
 
40
39
  destination_directory = File.join(@config.root, 'tmp')
@@ -56,7 +55,20 @@ module Geordi
56
55
  end
57
56
 
58
57
  def shell(options = {})
59
- server = options[:select_server] ? select_server : @config.primary_server
58
+ server_option = options[:select_server]
59
+ server_number = server_option.to_i
60
+
61
+ server = if server_option == 'select_server'
62
+ select_server
63
+ elsif server_number != 0 && server_number <= @config.servers.count
64
+ server_index = server_number - 1
65
+ @config.servers[server_index]
66
+ elsif server_option.nil?
67
+ @config.primary_server
68
+ else
69
+ Interaction.warn "Invalid server number: #{server_option}"
70
+ select_server
71
+ end
60
72
 
61
73
  remote_command = "cd #{@config.remote_root} && #{@config.shell}"
62
74
  remote_command << " -c '#{options[:remote_command]}'" if options[:remote_command]
@@ -0,0 +1,155 @@
1
+ require 'yaml'
2
+
3
+ require File.expand_path('util', __dir__)
4
+ require File.expand_path('interaction', __dir__)
5
+
6
+ module Geordi
7
+ class Settings
8
+ GLOBAL_SETTINGS_FILE_NAME = Util.testing? ? './tmp/global_settings.yml'.freeze : File.join(ENV['HOME'], '.config/geordi/global.yml').freeze
9
+ LOCAL_SETTINGS_FILE_NAME = Util.testing? ? './tmp/local_settings.yml'.freeze : './.geordi.yml'.freeze
10
+
11
+ ALLOWED_GLOBAL_SETTINGS = %w[ pivotal_tracker_api_key ].freeze
12
+ ALLOWED_LOCAL_SETTINGS = %w[ use_vnc pivotal_tracker_project_ids ].freeze
13
+
14
+ def initialize
15
+ read_settings
16
+ end
17
+
18
+ # Global settings
19
+ def pivotal_tracker_api_key
20
+ @global_settings['pivotal_tracker_api_key'] || gitpt_api_key_old || inquire_pt_api_key
21
+ end
22
+
23
+ def pivotal_tracker_api_key=(value)
24
+ @global_settings['pivotal_tracker_api_key'] = value
25
+ save_global_settings
26
+ end
27
+
28
+ # Local settings
29
+ # They should not be changed by geordi to avoid unexpected diffs, therefore
30
+ # there are no setters for these settings
31
+ def use_vnc?
32
+ @local_settings.fetch('use_vnc', true)
33
+ end
34
+
35
+ def pivotal_tracker_project_ids
36
+ project_ids = @local_settings['pivotal_tracker_project_ids'] || pt_project_ids_old
37
+
38
+ case project_ids
39
+ when Array
40
+ # nothing to do
41
+ when String
42
+ project_ids = project_ids.split(/[\s]+/).map(&:to_i)
43
+ when Integer
44
+ project_ids = [project_ids]
45
+ else
46
+ project_ids = []
47
+ end
48
+
49
+ if project_ids.empty?
50
+ puts
51
+ Geordi::Interaction.warn "Sorry, I could not find a project ID in .geordi.yml :("
52
+ puts
53
+
54
+ puts "Please put at least one Pivotal Tracker project id into the .geordi.yml file in this directory, e.g."
55
+ puts
56
+ puts "pivotal_tracker_project_ids:"
57
+ puts "- 123456"
58
+ puts
59
+ puts 'You may add multiple IDs.'
60
+ exit 1
61
+ end
62
+
63
+ project_ids
64
+ end
65
+
66
+ private
67
+
68
+ def read_settings
69
+ global_path = GLOBAL_SETTINGS_FILE_NAME
70
+ local_path = LOCAL_SETTINGS_FILE_NAME
71
+
72
+ if File.exists?(global_path)
73
+ global_settings = YAML.safe_load(File.read(global_path))
74
+ check_for_invalid_keys(global_settings, ALLOWED_GLOBAL_SETTINGS, global_path)
75
+ end
76
+
77
+ if File.exists?(local_path)
78
+ local_settings = YAML.safe_load(File.read(local_path))
79
+ check_for_invalid_keys(local_settings, ALLOWED_LOCAL_SETTINGS, local_path)
80
+ end
81
+
82
+ @global_settings = global_settings || {}
83
+ @local_settings = local_settings || {}
84
+ end
85
+
86
+ def check_for_invalid_keys(settings, allowed_keys, file)
87
+ invalid_keys = settings.keys - allowed_keys
88
+ unless invalid_keys.empty?
89
+ Geordi::Interaction.warn "Geordi detected unknown keys in #{file}.\n"
90
+
91
+ invalid_keys.sort.each do |key|
92
+ puts "* #{key}"
93
+ end
94
+
95
+ puts "\nAllowed keys are:"
96
+ allowed_keys.sort.each do |key|
97
+ puts "* #{key}"
98
+ end
99
+ puts
100
+
101
+ exit 1
102
+ end
103
+ end
104
+
105
+ def save_global_settings
106
+ global_path = GLOBAL_SETTINGS_FILE_NAME
107
+ global_directory = File.dirname(global_path)
108
+ FileUtils.mkdir_p(global_directory) unless File.directory? global_directory
109
+ File.open(global_path, 'w') do |file|
110
+ file.write @global_settings.to_yaml
111
+ end
112
+ end
113
+
114
+ # deprecated
115
+ def gitpt_api_key_old
116
+ file_path = File.join(ENV['HOME'], '.gitpt')
117
+ if File.exist?(file_path) && !Util.testing?
118
+ token = YAML.load_file(file_path).fetch :token
119
+ self.pivotal_tracker_api_key = token
120
+
121
+ Geordi::Interaction.warn "The ~/.gitpt file is deprecated."
122
+ Geordi::Interaction.note "The contained setting has been moved to ~/.config/geordi/global.yml."
123
+ Geordi::Interaction.note "If you don't need to work with an older version of geordi you can delete ~/.gitpt now."
124
+
125
+ token
126
+ end
127
+ end
128
+
129
+ def inquire_pt_api_key
130
+ Geordi::Interaction.warn 'Your settings are missing or invalid.'
131
+ Geordi::Interaction.warn "Please configure your Pivotal Tracker access."
132
+ token = Geordi::Interaction.prompt 'Your API key:'
133
+ self.pivotal_tracker_api_key = token
134
+ puts
135
+
136
+ token
137
+ end
138
+
139
+ # deprecated
140
+ def pt_project_ids_old
141
+ if File.exist?('.pt_project_id')
142
+ project_ids = File.read('.pt_project_id')
143
+ puts # Make sure to start on a new line (e.g. when invoked after a #print)
144
+ Geordi::Interaction.warn "The usage of the .pt_project_id file is deprecated."
145
+ Geordi::Interaction.note Util.strip_heredoc(<<-INSTRUCTIONS)
146
+ Please remove this file from your project and add or extend the .geordi.yml file with the following content:
147
+ pivotal_tracker_project_ids: #{project_ids}
148
+ INSTRUCTIONS
149
+
150
+ project_ids
151
+ end
152
+ end
153
+
154
+ end
155
+ end
@@ -62,13 +62,21 @@ module Geordi
62
62
  end
63
63
  end
64
64
 
65
+ def binstub(executable, *arguments)
66
+ binstub_file = "bin/#{executable}"
67
+
68
+ command = File.exists?(binstub_file) ? [binstub_file] : ['bundle exec', executable]
69
+ command.push(*arguments)
70
+ command.join(' ')
71
+ end
72
+
65
73
  def console_command(environment)
66
74
  if gem_major_version('rails') == 2
67
75
  'script/console ' + environment
68
76
  elsif gem_major_version('rails') == 3
69
- 'bundle exec rails console ' + environment
77
+ binstub 'rails', 'console', environment
70
78
  else
71
- "bundle exec rails console -e #{environment}"
79
+ binstub 'rails', 'console -e', environment
72
80
  end
73
81
  end
74
82
 
@@ -76,7 +84,7 @@ module Geordi
76
84
  if gem_major_version('rails') == 2
77
85
  'script/server ""'
78
86
  else
79
- 'bundle exec rails server'
87
+ binstub 'rails', 'server'
80
88
  end
81
89
  end
82
90
 
@@ -93,7 +101,7 @@ module Geordi
93
101
  ENV['GEORDI_TESTING_STAGED_CHANGES'] == 'true'
94
102
  else
95
103
  statuses = `git status --porcelain`.split("\n")
96
- statuses.any? { |l| l.start_with? /[A-Z]/i }
104
+ statuses.any? { |l| /^[A-Z]/i =~ l }
97
105
  end
98
106
  end
99
107