geordi 9.6.1 → 10.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +4 -3
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +1 -1
- data/README.md +24 -13
- data/Rakefile +12 -7
- data/lib/geordi/chromedriver_updater.rb +20 -9
- data/lib/geordi/commands/capistrano.rb +5 -0
- data/lib/geordi/commands/chromedriver_update.rb +7 -1
- data/lib/geordi/commands/clean.rb +1 -1
- data/lib/geordi/commands/commit.rb +2 -1
- data/lib/geordi/commands/console.rb +5 -1
- data/lib/geordi/commands/cucumber.rb +4 -2
- data/lib/geordi/commands/delete_dumps.rb +3 -2
- data/lib/geordi/commands/deploy.rb +1 -1
- data/lib/geordi/commands/drop_databases.rb +17 -6
- data/lib/geordi/commands/dump.rb +1 -1
- data/lib/geordi/commands/rake.rb +1 -1
- data/lib/geordi/commands/remove_executable_flags.rb +1 -1
- data/lib/geordi/commands/rspec.rb +7 -4
- data/lib/geordi/commands/server.rb +1 -1
- data/lib/geordi/commands/setup.rb +4 -1
- data/lib/geordi/commands/shell.rb +2 -1
- data/lib/geordi/commands/tests.rb +1 -1
- data/lib/geordi/commands/update.rb +3 -1
- data/lib/geordi/db_cleaner.rb +124 -82
- data/lib/geordi/dump_loader.rb +10 -6
- data/lib/geordi/hint.rb +1 -1
- data/lib/geordi/settings.rb +13 -1
- data/lib/geordi/util.rb +19 -13
- data/lib/geordi/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7ba836f9a4c3651c05372c9a6f0f09cc86a4ed192020c7a0e9def2b5742b76b
|
4
|
+
data.tar.gz: 2668192b49eb8c16bcac3cdc1563f77b7d09c0759fa51ef7ea80288732fcb4dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68a50772d7eca079e66034805f87362dca94fa969ee7bd3095fa5c64236af99c1e28658742fa9ff151f5930e23fed1035f57f8c432d3528545498e6f7fb58a76
|
7
|
+
data.tar.gz: e24dc966d01cef499829b00337bb221cc662bfe080421010c72791bb0954388fb4d2fd13a42ce689405133870b976349b42b995443b354d2c04d6239f9c4934b
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -10,6 +10,20 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
|
|
10
10
|
### Breaking changes
|
11
11
|
|
12
12
|
|
13
|
+
# 10.0.0 2024-03-07
|
14
|
+
|
15
|
+
### Compatible changes
|
16
|
+
* `console` command: IRB flags stored in the global config file are automatically passed on to IRB
|
17
|
+
* `console` command: Improve interrupt handling in local Rails console
|
18
|
+
* `rspec` and `cucumber` commands: Do not fail or exit if chromedriver update fails
|
19
|
+
* Fix detection of IRB version
|
20
|
+
* Add new hints to 'Did you know'
|
21
|
+
|
22
|
+
### Breaking changes
|
23
|
+
* `dump`-command: Drop and recreate the database before restoring a postgres dump
|
24
|
+
* `drop_databases`-command: Use local user per default to connect to database
|
25
|
+
|
26
|
+
|
13
27
|
# 9.6.1 2023-09-22
|
14
28
|
|
15
29
|
### Compatible changes
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -19,6 +19,8 @@ You may abbreviate commands by typing only their first letters, e.g. `geordi
|
|
19
19
|
con` will boot a development console, `geordi set -t` will setup a project and
|
20
20
|
run tests afterwards.
|
21
21
|
|
22
|
+
Commands will occasionally print "did you know" hints of other Geordi features.
|
23
|
+
|
22
24
|
You can always run `geordi help <command>` to quickly look up command help.
|
23
25
|
|
24
26
|
### `geordi branch`
|
@@ -51,9 +53,6 @@ Setting `auto_update_chromedriver` to `true` in your global Geordi config file
|
|
51
53
|
(`~/.config/geordi/global.yml`), will automatically update chromedriver before
|
52
54
|
cucumber tests if a newer chromedriver version is available.
|
53
55
|
|
54
|
-
**Options**
|
55
|
-
- `[--quiet-if-matching], [--no-quiet-if-matching]`: Suppress notification if chromedriver is already on the latest version
|
56
|
-
|
57
56
|
|
58
57
|
### `geordi clean`
|
59
58
|
Remove unneeded files from the current directory.
|
@@ -80,6 +79,8 @@ Remote: `geordi console staging`
|
|
80
79
|
Selecting the server: `geordi console staging -s` shows a menu with all available
|
81
80
|
servers. When passed a number, directly connects to the selected server.
|
82
81
|
|
82
|
+
IRB flags can be given as `irb_flags: '...'` in the global Geordi config file (`~/.config/geordi/global.yml`).
|
83
|
+
|
83
84
|
**Options**
|
84
85
|
- `-s, [--select-server=[SERVER_NUMBER]]`: Select a server to connect to
|
85
86
|
|
@@ -108,7 +109,7 @@ variable like this: `PARALLEL_TEST_PROCESSORS=6 geordi cucumber`
|
|
108
109
|
|
109
110
|
|
110
111
|
### `geordi delete-dumps [DIRECTORY]`
|
111
|
-
|
112
|
+
Help deleting database dump files (*.dump).
|
112
113
|
|
113
114
|
Example: `geordi delete-dumps` or `geordi delete-dumps ~/tmp/dumps`
|
114
115
|
|
@@ -166,14 +167,18 @@ and offer to delete them. Excluded are databases that are whitelisted. This come
|
|
166
167
|
in handy when you're keeping your currently active projects in the whitelist files
|
167
168
|
and perform regular housekeeping with Geordi.
|
168
169
|
|
170
|
+
Per default, Geordi will try to connect to the databases as a local user without
|
171
|
+
password authorization.
|
172
|
+
|
169
173
|
Geordi will ask for confirmation before actually dropping databases and will
|
170
174
|
offer to edit the whitelist instead.
|
171
175
|
|
172
176
|
**Options**
|
173
|
-
- `-P, [--postgres-only], [--no-postgres-only]`: Only clean
|
177
|
+
- `-P, [--postgres-only], [--no-postgres-only]`: Only clean PostgreSQL
|
174
178
|
- `-M, [--mysql-only], [--no-mysql-only]`: Only clean MySQL/MariaDB
|
175
|
-
- `[--postgres=PORT_OR_SOCKET]`: Use
|
179
|
+
- `[--postgres=PORT_OR_SOCKET]`: Use PostgreSQL port or socket
|
176
180
|
- `[--mysql=PORT_OR_SOCKET]`: Use MySQL/MariaDB port or socket
|
181
|
+
- `-S, [--sudo], [--no-sudo]`: Access databases as root
|
177
182
|
|
178
183
|
|
179
184
|
### `geordi dump [TARGET]`
|
@@ -396,19 +401,25 @@ Adding a new command
|
|
396
401
|
---------------
|
397
402
|
|
398
403
|
Copy `lib/geordi/COMMAND_TEMPLATE` to `lib/geordi/commands/your_command` and
|
399
|
-
edit it to do what you need it to do. Please add
|
400
|
-
command; see
|
404
|
+
edit it to do what you need it to do. Please add appropriate tests for the new
|
405
|
+
command; see existing tests for inspiration.
|
401
406
|
|
402
|
-
To try Geordi locally, call it like this:
|
403
407
|
|
404
|
-
|
405
|
-
|
408
|
+
Running Geordi locally
|
409
|
+
----------------------
|
410
|
+
|
411
|
+
To run Geordi without installation, call it like this:
|
412
|
+
|
413
|
+
ruby -I lib exe/geordi
|
414
|
+
|
415
|
+
# With debugger
|
416
|
+
ruby -r byebug -I lib exe/geordi
|
406
417
|
|
407
418
|
# From another directory
|
408
419
|
ruby -I ../geordi/lib ../geordi/exe/geordi
|
409
420
|
|
410
|
-
#
|
411
|
-
ruby
|
421
|
+
# Run Geordi with the Ruby version of that other directory
|
422
|
+
RBENV_VERSION=$(<.ruby-version) ruby -I ../geordi/lib ../geordi/exe/geordi
|
412
423
|
|
413
424
|
You can also *install* Geordi locally from its project directory with
|
414
425
|
`rake install`. Make sure to switch to the expected Ruby version before.
|
data/Rakefile
CHANGED
@@ -2,10 +2,14 @@ require 'bundler'
|
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
4
|
desc 'Default: Run all tests'
|
5
|
-
task default: :features
|
5
|
+
task default: [:rspec, :features]
|
6
6
|
|
7
7
|
task :features do
|
8
|
-
|
8
|
+
system 'bundle exec cucumber'
|
9
|
+
end
|
10
|
+
|
11
|
+
task :rspec do
|
12
|
+
system 'bundle exec rspec'
|
9
13
|
end
|
10
14
|
|
11
15
|
task :readme do
|
@@ -32,6 +36,8 @@ You may abbreviate commands by typing only their first letters, e.g. `geordi
|
|
32
36
|
con` will boot a development console, `geordi set -t` will setup a project and
|
33
37
|
run tests afterwards.
|
34
38
|
|
39
|
+
Commands will occasionally print "did you know" hints of other Geordi features.
|
40
|
+
|
35
41
|
You can always run `geordi help <command>` to quickly look up command help.
|
36
42
|
TEXT
|
37
43
|
|
@@ -42,12 +48,11 @@ You can always run `geordi help <command>` to quickly look up command help.
|
|
42
48
|
geordi_section << "#{command.description.sub /(\.)?$/, '.'}\n\n"
|
43
49
|
geordi_section << "#{command.long_description.strip}\n\n" if command.long_description
|
44
50
|
|
45
|
-
|
46
|
-
geordi_section << "**Options**\n"
|
47
|
-
# Taken from thor-1.0.1/lib/thor/base.rb:557
|
48
|
-
command.options.values.each do |option|
|
49
|
-
next if option.hide
|
51
|
+
visible_options = command.options.reject {|_option_name, option_object| option_object.hide }
|
50
52
|
|
53
|
+
if visible_options.any?
|
54
|
+
geordi_section << "**Options**\n"
|
55
|
+
visible_options.values.each do |option|
|
51
56
|
geordi_section << "- `#{option.usage}`"
|
52
57
|
geordi_section << ": #{option.description}" if option.description
|
53
58
|
geordi_section << "\n"
|
@@ -6,6 +6,8 @@ require 'fileutils'
|
|
6
6
|
|
7
7
|
module Geordi
|
8
8
|
class ChromedriverUpdater
|
9
|
+
class ProcessingError < StandardError; end
|
10
|
+
|
9
11
|
VERSIONS_PER_MILESTONES_URL = "https://googlechromelabs.github.io/chrome-for-testing/latest-versions-per-milestone-with-downloads.json"
|
10
12
|
|
11
13
|
def run(options)
|
@@ -18,6 +20,10 @@ module Geordi
|
|
18
20
|
else
|
19
21
|
update_chromedriver(latest_chromedriver_version)
|
20
22
|
end
|
23
|
+
|
24
|
+
rescue ProcessingError => e
|
25
|
+
interaction_method = (options[:exit_on_failure] == false) ? :warn : :fail
|
26
|
+
Interaction.public_send(interaction_method, e.message)
|
21
27
|
end
|
22
28
|
|
23
29
|
private
|
@@ -29,7 +35,7 @@ module Geordi
|
|
29
35
|
end
|
30
36
|
|
31
37
|
if !status.success? || chrome_version.nil?
|
32
|
-
|
38
|
+
raise ProcessingError, 'Could not determine the version of Google Chrome.'
|
33
39
|
else
|
34
40
|
chrome_version
|
35
41
|
end
|
@@ -44,7 +50,7 @@ module Geordi
|
|
44
50
|
end
|
45
51
|
|
46
52
|
if !status.success? || chromedriver_version.nil?
|
47
|
-
|
53
|
+
raise ProcessingError, 'Could not determine the version of chromedriver.'
|
48
54
|
else
|
49
55
|
chromedriver_version
|
50
56
|
end
|
@@ -62,11 +68,11 @@ module Geordi
|
|
62
68
|
unzip(chromedriver_zip, File.expand_path('~/bin'))
|
63
69
|
|
64
70
|
# We need to determine the version again, as it could be nil in case no chromedriver was installed before
|
65
|
-
Interaction.success "Chromedriver updated to
|
71
|
+
Interaction.success "Chromedriver updated to #{determine_chromedriver_version}."
|
66
72
|
end
|
67
73
|
|
68
74
|
def download_chromedriver(version)
|
69
|
-
fetch_response(chromedriver_url(version), "Could not download chromedriver
|
75
|
+
fetch_response(chromedriver_url(version), "Could not download chromedriver #{version}.") do |response|
|
70
76
|
file = Tempfile.new(%w[chromedriver .zip])
|
71
77
|
file.write(response.body)
|
72
78
|
|
@@ -81,8 +87,13 @@ module Geordi
|
|
81
87
|
if response.is_a?(Net::HTTPSuccess)
|
82
88
|
yield(response)
|
83
89
|
else
|
84
|
-
|
90
|
+
raise ProcessingError, error_message
|
85
91
|
end
|
92
|
+
|
93
|
+
# Rescue Errno::NOERROR, Errno::ENOENT, Errno::EACCES, Errno::EFAULT, Errno::ECONNREFUSED, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EHOSTDOWN, Errno::EHOSTUNREACH, ...,
|
94
|
+
# all of which are a subclass of SystemCallError
|
95
|
+
rescue SystemCallError => e
|
96
|
+
raise ProcessingError, "Request failed: #{e.message}"
|
86
97
|
end
|
87
98
|
|
88
99
|
def chromedriver_url(chrome_version)
|
@@ -94,7 +105,7 @@ module Geordi
|
|
94
105
|
if chromedriver && chromedriver["url"]
|
95
106
|
chromedriver["url"]
|
96
107
|
else
|
97
|
-
|
108
|
+
raise ProcessingError, "Could not find chromedriver download url for Chrome #{chrome_version}."
|
98
109
|
end
|
99
110
|
end
|
100
111
|
|
@@ -105,7 +116,7 @@ module Geordi
|
|
105
116
|
begin
|
106
117
|
chromedriver_download_data = JSON.parse(response.body)
|
107
118
|
rescue JSON::ParserError
|
108
|
-
|
119
|
+
raise ProcessingError, "Could not parse chromedriver download data."
|
109
120
|
end
|
110
121
|
@chromedriver_download_data = chromedriver_download_data
|
111
122
|
end
|
@@ -113,14 +124,14 @@ module Geordi
|
|
113
124
|
|
114
125
|
def latest_version(chrome_version)
|
115
126
|
latest_version = chromedriver_download_data.dig("milestones", milestone_version(chrome_version), "version")
|
116
|
-
latest_version ||
|
127
|
+
latest_version || raise(ProcessingError, "Could not find matching chromedriver for Chrome #{chrome_version}.")
|
117
128
|
end
|
118
129
|
|
119
130
|
def unzip(zip, output_dir)
|
120
131
|
_stdout_str, _error_str, status = Open3.capture3('unzip', '-d', output_dir, '-o', zip.path)
|
121
132
|
|
122
133
|
unless status.success?
|
123
|
-
|
134
|
+
raise ProcessingError, "Could not unzip #{zip.path}."
|
124
135
|
end
|
125
136
|
|
126
137
|
# the archive contains a folder in which the relevant files are located. These files must be moved to ~/bin.
|
@@ -10,11 +10,17 @@ Setting `auto_update_chromedriver` to `true` in your global Geordi config file
|
|
10
10
|
cucumber tests if a newer chromedriver version is available.
|
11
11
|
LONGDESC
|
12
12
|
|
13
|
-
option :quiet_if_matching, type: :boolean, default: false,
|
13
|
+
option :quiet_if_matching, type: :boolean, default: false, hide: true,
|
14
14
|
desc: 'Suppress notification if chromedriver is already on the latest version'
|
15
|
+
option :exit_on_failure, type: :boolean, default: true, hide: true,
|
16
|
+
desc: "Exit with status code 1, if an error occurs."
|
15
17
|
|
16
18
|
def chromedriver_update
|
17
19
|
require 'geordi/chromedriver_updater'
|
18
20
|
|
19
21
|
ChromedriverUpdater.new.run(options)
|
22
|
+
|
23
|
+
Hint.did_you_know [
|
24
|
+
'Geordi can automatically keep chromedriver up-to-date. See `geordi help chromedriver-update`.',
|
25
|
+
] unless options.quiet_if_matching
|
20
26
|
end
|
@@ -6,6 +6,8 @@ Remote: `geordi console staging`
|
|
6
6
|
|
7
7
|
Selecting the server: `geordi console staging -s` shows a menu with all available
|
8
8
|
servers. When passed a number, directly connects to the selected server.
|
9
|
+
|
10
|
+
IRB flags can be given as `irb_flags: '...'` in the global Geordi config file (`~/.config/geordi/global.yml`).
|
9
11
|
LONGDESC
|
10
12
|
|
11
13
|
# This option is duplicated in shelll.rb
|
@@ -18,6 +20,7 @@ def console(target = 'development', *_args)
|
|
18
20
|
Hint.did_you_know [
|
19
21
|
:shelll,
|
20
22
|
[:console, :select_server],
|
23
|
+
'You only need to type the unique prefix of a command to run it. `geordi con` will work as well.',
|
21
24
|
]
|
22
25
|
|
23
26
|
if target == 'development'
|
@@ -27,7 +30,8 @@ def console(target = 'development', *_args)
|
|
27
30
|
Interaction.announce 'Opening a local Rails console'
|
28
31
|
|
29
32
|
command = Util.console_command(target)
|
30
|
-
|
33
|
+
# Exec has better behavior on Ctrl + C
|
34
|
+
Util.run!(command, exec: true)
|
31
35
|
else
|
32
36
|
Interaction.announce 'Opening a Rails console on ' + target
|
33
37
|
|
@@ -49,7 +49,7 @@ def cucumber(*args)
|
|
49
49
|
invoke_geordi 'bundle_install'
|
50
50
|
invoke_geordi 'yarn_install'
|
51
51
|
if settings.auto_update_chromedriver
|
52
|
-
invoke_geordi 'chromedriver_update', quiet_if_matching: true
|
52
|
+
invoke_geordi 'chromedriver_update', quiet_if_matching: true, exit_on_failure: false
|
53
53
|
end
|
54
54
|
|
55
55
|
arguments = args
|
@@ -77,7 +77,9 @@ def cucumber(*args)
|
|
77
77
|
[:cucumber, :modified],
|
78
78
|
[:cucumber, :containing],
|
79
79
|
[:cucumber, :debug],
|
80
|
-
|
80
|
+
[:cucumber, :rerun],
|
81
|
+
'Geordi can automatically keep chromedriver up-to-date. See `geordi help chromedriver-update`.',
|
82
|
+
'You only need to type the unique prefix of a command to run it. `geordi cuc` will work as well.',
|
81
83
|
]
|
82
84
|
else
|
83
85
|
Interaction.note 'Cucumber not employed.'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
desc 'delete-dumps [DIRECTORY]', '
|
1
|
+
desc 'delete-dumps [DIRECTORY]', 'Help deleting database dump files (*.dump)'
|
2
2
|
long_desc <<-LONGDESC
|
3
3
|
Example: `geordi delete-dumps` or `geordi delete-dumps ~/tmp/dumps`
|
4
4
|
|
@@ -41,6 +41,7 @@ def delete_dumps(*locations)
|
|
41
41
|
|
42
42
|
Hint.did_you_know [
|
43
43
|
:clean,
|
44
|
-
:drop_databases
|
44
|
+
:drop_databases,
|
45
|
+
:dump,
|
45
46
|
]
|
46
47
|
end
|
@@ -7,18 +7,23 @@ and offer to delete them. Excluded are databases that are whitelisted. This come
|
|
7
7
|
in handy when you're keeping your currently active projects in the whitelist files
|
8
8
|
and perform regular housekeeping with Geordi.
|
9
9
|
|
10
|
+
Per default, Geordi will try to connect to the databases as a local user without
|
11
|
+
password authorization.
|
12
|
+
|
10
13
|
Geordi will ask for confirmation before actually dropping databases and will
|
11
14
|
offer to edit the whitelist instead.
|
12
15
|
LONGDESC
|
13
16
|
|
14
17
|
option :postgres_only, aliases: '-P', type: :boolean,
|
15
|
-
desc: 'Only clean
|
18
|
+
desc: 'Only clean PostgreSQL', default: false
|
16
19
|
option :mysql_only, aliases: '-M', type: :boolean,
|
17
20
|
desc: 'Only clean MySQL/MariaDB', default: false
|
18
21
|
option :postgres, banner: 'PORT_OR_SOCKET',
|
19
|
-
desc: 'Use
|
22
|
+
desc: 'Use PostgreSQL port or socket'
|
20
23
|
option :mysql, banner: 'PORT_OR_SOCKET',
|
21
24
|
desc: 'Use MySQL/MariaDB port or socket'
|
25
|
+
option :sudo, aliases: '-S', type: :boolean, default: false,
|
26
|
+
desc: 'Access databases as root'
|
22
27
|
|
23
28
|
def drop_databases
|
24
29
|
require 'geordi/db_cleaner'
|
@@ -42,13 +47,19 @@ def drop_databases
|
|
42
47
|
postgres_flags = "--port=#{options.postgres}"
|
43
48
|
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
unless options.sudo
|
51
|
+
Interaction.note 'Assuming your local user has permission to drop databases. Run with `--sudo` to use sudo.'
|
52
|
+
end
|
53
|
+
|
54
|
+
extra_flags = {
|
55
|
+
'mysql' => mysql_flags,
|
56
|
+
'postgres' => postgres_flags,
|
57
|
+
}
|
58
|
+
cleaner = DBCleaner.new(extra_flags, sudo: options.sudo)
|
48
59
|
cleaner.clean_mysql unless options.postgres_only
|
49
60
|
cleaner.clean_postgres unless options.mysql_only
|
50
61
|
|
51
62
|
Hint.did_you_know [
|
52
|
-
:delete_dumps
|
63
|
+
:delete_dumps,
|
53
64
|
]
|
54
65
|
end
|
data/lib/geordi/commands/dump.rb
CHANGED
@@ -73,6 +73,6 @@ def dump(target = nil, *_args)
|
|
73
73
|
:delete_dumps,
|
74
74
|
:drop_databases,
|
75
75
|
:migrate,
|
76
|
-
'Geordi can load a dump directly into the local database if passed a Capistrano stage and the option -l. See `geordi help dump`.'
|
76
|
+
'Geordi can load a dump directly into the local database if passed a Capistrano stage and the option -l. See `geordi help dump`.',
|
77
77
|
]
|
78
78
|
end
|
data/lib/geordi/commands/rake.rb
CHANGED
@@ -17,7 +17,7 @@ def rspec(*files)
|
|
17
17
|
invoke_geordi 'bundle_install'
|
18
18
|
invoke_geordi 'yarn_install'
|
19
19
|
if settings.auto_update_chromedriver && Util.gem_available?('selenium-webdriver')
|
20
|
-
invoke_geordi 'chromedriver_update', quiet_if_matching: true
|
20
|
+
invoke_geordi 'chromedriver_update', quiet_if_matching: true, exit_on_failure: false
|
21
21
|
end
|
22
22
|
|
23
23
|
Interaction.announce 'Running specs'
|
@@ -46,10 +46,13 @@ def rspec(*files)
|
|
46
46
|
puts
|
47
47
|
Util.run!(command.join(' '), fail_message: 'Specs failed.')
|
48
48
|
|
49
|
-
Hint.did_you_know [
|
50
|
-
:cucumber
|
51
|
-
]
|
52
49
|
end
|
50
|
+
|
51
|
+
Hint.did_you_know [
|
52
|
+
:cucumber,
|
53
|
+
'Geordi can automatically keep chromedriver up-to-date. See `geordi help chromedriver-update`.',
|
54
|
+
'You only need to type the unique prefix of a command to run it. `geordi rs` will work as well.',
|
55
|
+
]
|
53
56
|
else
|
54
57
|
Interaction.note 'RSpec not employed.'
|
55
58
|
end
|
@@ -28,7 +28,10 @@ def setup
|
|
28
28
|
Interaction.success 'Successfully set up the project.'
|
29
29
|
|
30
30
|
Hint.did_you_know [
|
31
|
-
:update
|
31
|
+
:update,
|
32
|
+
:security_update,
|
33
|
+
[:setup, :dump],
|
34
|
+
[:setup, :test],
|
32
35
|
] unless options.dump || options.test
|
33
36
|
|
34
37
|
invoke_geordi 'dump', options.dump, load: true if options.dump
|
@@ -16,7 +16,8 @@ def shelll(target, *_args)
|
|
16
16
|
require 'geordi/remote'
|
17
17
|
|
18
18
|
Hint.did_you_know [
|
19
|
-
:console
|
19
|
+
:console,
|
20
|
+
'You only need to type the unique prefix of a command to run it. `geordi sh` will work as well.',
|
20
21
|
]
|
21
22
|
|
22
23
|
Interaction.announce 'Opening a shell on ' + target
|
@@ -28,7 +28,9 @@ def update
|
|
28
28
|
Interaction.success 'Successfully updated the project.'
|
29
29
|
|
30
30
|
Hint.did_you_know [
|
31
|
-
:setup
|
31
|
+
:setup,
|
32
|
+
[:update, :dump],
|
33
|
+
[:update, :test],
|
32
34
|
] unless options.dump || options.test
|
33
35
|
|
34
36
|
invoke_geordi 'dump', options.dump, load: true if options.dump
|
data/lib/geordi/db_cleaner.rb
CHANGED
@@ -3,37 +3,48 @@ require 'open3'
|
|
3
3
|
require 'tempfile'
|
4
4
|
|
5
5
|
module Geordi
|
6
|
+
|
7
|
+
DatabaseError = Class.new(StandardError)
|
8
|
+
|
6
9
|
class DBCleaner
|
7
10
|
|
8
|
-
def initialize(extra_flags)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def initialize(extra_flags, sudo: false)
|
12
|
+
@sudo = sudo
|
13
|
+
|
14
|
+
if @sudo
|
15
|
+
Interaction.note 'Please enter your sudo password when asked.'
|
16
|
+
puts "We're going to run `sudo -u postgres psql` for PostgreSQL"
|
17
|
+
puts ' and `sudo mysql` for MariaDB (which uses PAM auth)'
|
18
|
+
`sudo true`
|
19
|
+
Interaction.fail 'sudo access is required for database operations as database users' if $? != 0
|
20
|
+
end
|
21
|
+
|
14
22
|
@derivative_dbname = /_(test\d*|development|cucumber)$/
|
15
|
-
base_directory = ENV['XDG_CONFIG_HOME']
|
16
|
-
base_directory
|
17
|
-
@
|
18
|
-
FileUtils.mkdir_p(@
|
23
|
+
@base_directory = ENV['XDG_CONFIG_HOME']
|
24
|
+
@base_directory ||= Dir.home.to_s
|
25
|
+
@allowlist_directory = File.join(@base_directory, '.config', 'geordi', 'allowlists')
|
26
|
+
FileUtils.mkdir_p(@allowlist_directory) unless File.directory? @allowlist_directory
|
27
|
+
if File.directory?(legacy_allowlist_directory)
|
28
|
+
move_allowlist_files
|
29
|
+
end
|
19
30
|
@mysql_command = decide_mysql_command(extra_flags['mysql'])
|
20
31
|
@postgres_command = decide_postgres_command(extra_flags['postgres'])
|
21
32
|
end
|
22
33
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
Geordi::Util.stripped_lines(File.read(
|
34
|
+
def edit_allowlist(dbtype)
|
35
|
+
allowlist = allowlist_fname(dbtype)
|
36
|
+
allowlisted_dbs = if File.exist? allowlist
|
37
|
+
Geordi::Util.stripped_lines(File.read(allowlist))\
|
27
38
|
.delete_if { |l| l.start_with? '#' }
|
28
39
|
else
|
29
40
|
[]
|
30
41
|
end
|
31
42
|
all_dbs = list_all_dbs(dbtype)
|
32
|
-
tmp = Tempfile.open("
|
43
|
+
tmp = Tempfile.open("geordi_allowlist_#{dbtype}")
|
33
44
|
tmp.write <<~HEREDOC
|
34
|
-
# Put each
|
45
|
+
# Put each allowlisted database on a new line.
|
35
46
|
# System databases will never be deleted.
|
36
|
-
# When you
|
47
|
+
# When you allowlist foo, foo_development and foo_test\\d* are allowlisted, too.
|
37
48
|
# This works even if foo does not exist. Also, you will only see foo in this list.
|
38
49
|
#
|
39
50
|
# Syntax: keep foo
|
@@ -41,32 +52,32 @@ module Geordi
|
|
41
52
|
HEREDOC
|
42
53
|
tmpfile_content = Array.new
|
43
54
|
all_dbs.each do |db|
|
44
|
-
next if
|
55
|
+
next if is_allowlisted?(dbtype, db)
|
45
56
|
next if is_protected?(dbtype, db)
|
46
57
|
db.sub!(@derivative_dbname, '')
|
47
58
|
tmpfile_content.push(['drop', db])
|
48
59
|
end
|
49
|
-
|
50
|
-
|
51
|
-
# Remove 'keep' word from
|
52
|
-
# does not save 'keep' or 'drop' to the
|
53
|
-
# of all
|
54
|
-
# the
|
55
|
-
# prefix to 'keep'. Everything prefixed 'drop' is not considered
|
56
|
-
# not written to the
|
60
|
+
warn_manual_allowlist = false
|
61
|
+
allowlisted_dbs.each do |db_name|
|
62
|
+
# Remove 'keep' word from allowlist entries. This is not normally required since geordi
|
63
|
+
# does not save 'keep' or 'drop' to the allowlist file on disk but rather saves a list
|
64
|
+
# of all allowlisted db names and just presents the keep/drop information while editing
|
65
|
+
# the allowlist to supply users a list of databases they can allowlist by changing the
|
66
|
+
# prefix to 'keep'. Everything prefixed 'drop' is not considered allowlisted and thus
|
67
|
+
# not written to the allowlist file on disk.
|
57
68
|
#
|
58
|
-
# However, if users manually edit their
|
69
|
+
# However, if users manually edit their allowlist files they might use the keep/drop
|
59
70
|
# syntax they're familiar with.
|
60
71
|
if db_name.start_with? 'keep '
|
61
72
|
db_name.gsub!(/keep /, '')
|
62
73
|
db_name = db_name.split[1..-1].join(' ')
|
63
|
-
|
74
|
+
warn_manual_allowlist = true
|
64
75
|
end
|
65
76
|
tmpfile_content.push(['keep', db_name]) unless db_name.empty?
|
66
77
|
end
|
67
|
-
if
|
78
|
+
if warn_manual_allowlist
|
68
79
|
Interaction.warn <<~ERROR_MSG
|
69
|
-
Your
|
80
|
+
Your allowlist #{allowlist} seems to have been generated manually.
|
70
81
|
In that case, make sure to use only one database name per line and omit the 'keep' prefix."
|
71
82
|
|
72
83
|
Launching the editor.
|
@@ -81,29 +92,29 @@ module Geordi
|
|
81
92
|
texteditor = Geordi::Util.decide_texteditor
|
82
93
|
system("#{texteditor} #{tmp.path}")
|
83
94
|
File.open(tmp.path, 'r') do |wl_edited|
|
84
|
-
|
85
|
-
|
95
|
+
allowlisted_dbs = []
|
96
|
+
allowlist_storage = File.open(allowlist, 'w')
|
86
97
|
lines = Geordi::Util.stripped_lines(wl_edited.read)
|
87
98
|
lines.each do |line|
|
88
99
|
next if line.start_with?('#')
|
89
100
|
unless line.split.length == 2
|
90
|
-
Interaction.fail "Invalid edit to
|
101
|
+
Interaction.fail "Invalid edit to allowlist file: \`#{line}\` - Syntax is: ^[keep|drop] dbname$"
|
91
102
|
end
|
92
103
|
unless %w[keep drop k d].include? line.split.first
|
93
|
-
Interaction.fail "Invalid edit to
|
104
|
+
Interaction.fail "Invalid edit to allowlist file: \`#{line}\` - must start with either drop or keep."
|
94
105
|
end
|
95
106
|
db_status, db_name = line.split
|
96
107
|
if db_status == 'keep'
|
97
|
-
|
98
|
-
|
108
|
+
allowlisted_dbs.push db_name
|
109
|
+
allowlist_storage.write(db_name << "\n")
|
99
110
|
end
|
100
111
|
end
|
101
|
-
|
112
|
+
allowlist_storage.close
|
102
113
|
end
|
103
114
|
end
|
104
115
|
|
105
116
|
def decide_mysql_command(extra_flags)
|
106
|
-
cmd = 'sudo mysql'
|
117
|
+
cmd = @sudo ? 'sudo mysql' : 'mysql'
|
107
118
|
unless extra_flags.nil?
|
108
119
|
if extra_flags.include? 'port'
|
109
120
|
port = Integer(extra_flags.split('=')[1].split[0])
|
@@ -111,24 +122,27 @@ module Geordi
|
|
111
122
|
end
|
112
123
|
cmd << " #{extra_flags}"
|
113
124
|
end
|
114
|
-
|
115
|
-
|
116
|
-
#
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
125
|
+
|
126
|
+
if @sudo
|
127
|
+
Open3.popen3("#{cmd} -e 'QUIT'") do |_stdin, _stdout, stderr, thread|
|
128
|
+
break if thread.value.exitstatus == 0
|
129
|
+
# sudo mysql was not successful, switching to mysql-internal user management
|
130
|
+
mysql_error = stderr.read.lines[0].chomp.strip.split[1]
|
131
|
+
if %w[1045 1698].include? mysql_error # authentication failed
|
132
|
+
cmd = 'mysql -uroot'
|
133
|
+
cmd << " #{extra_flags}" unless extra_flags.nil?
|
134
|
+
unless File.exist? File.join(Dir.home, '.my.cnf')
|
135
|
+
Interaction.note "Please enter your MySQL/MariaDB password for account 'root'."
|
136
|
+
Interaction.warn "You should create a ~/.my.cnf file instead, or you'll need to enter your MySQL root password for each db."
|
137
|
+
Interaction.note 'See https://makandracards.com/makandra/50813-store-mysql-passwords-for-development for more information.'
|
138
|
+
cmd << ' -p' # need to ask for password now
|
139
|
+
end
|
140
|
+
Open3.popen3("#{cmd} -e 'QUIT'") do |_stdin_2, _stdout_2, _stderr_2, thread_2|
|
141
|
+
Interaction.fail 'Could not connect to MySQL/MariaDB' unless thread_2.value.exitstatus == 0
|
142
|
+
end
|
143
|
+
elsif mysql_error == '2013' # connection to port or socket failed
|
144
|
+
Interaction.fail 'MySQL/MariaDB connection failed, is this the correct port?'
|
129
145
|
end
|
130
|
-
elsif mysql_error == '2013' # connection to port or socket failed
|
131
|
-
Interaction.fail 'MySQL/MariaDB connection failed, is this the correct port?'
|
132
146
|
end
|
133
147
|
end
|
134
148
|
cmd
|
@@ -136,7 +150,7 @@ module Geordi
|
|
136
150
|
private :decide_mysql_command
|
137
151
|
|
138
152
|
def decide_postgres_command(extra_flags)
|
139
|
-
cmd = 'sudo -u postgres psql'
|
153
|
+
cmd = @sudo ? 'sudo -u postgres psql' : 'psql'
|
140
154
|
unless extra_flags.nil?
|
141
155
|
begin
|
142
156
|
port = Integer(extra_flags.split('=')[1])
|
@@ -157,28 +171,38 @@ module Geordi
|
|
157
171
|
else
|
158
172
|
list_all_mysql_dbs
|
159
173
|
end
|
174
|
+
rescue DatabaseError
|
175
|
+
Interaction.fail 'Connection to database could not be established. Try running again with --sudo.'
|
160
176
|
end
|
161
177
|
|
162
178
|
def list_all_postgres_dbs
|
163
|
-
|
179
|
+
output, _error, status = Open3.capture3("#{@postgres_command} -t -A -c 'SELECT DATNAME FROM pg_database WHERE datistemplate = false'")
|
180
|
+
|
181
|
+
raise DatabaseError unless status.success?
|
182
|
+
|
183
|
+
output.split
|
164
184
|
end
|
165
185
|
|
166
186
|
def list_all_mysql_dbs
|
167
187
|
if @mysql_command.include? '-p'
|
168
|
-
|
188
|
+
Interaction.note "Please enter your MySQL/MariaDB account 'root' for: list all databases"
|
169
189
|
end
|
170
|
-
|
190
|
+
output, _error, status = Open3.capture3("#{@mysql_command} -B -N -e 'show databases'")
|
191
|
+
|
192
|
+
raise DatabaseError unless status.success?
|
193
|
+
|
194
|
+
output.split
|
171
195
|
end
|
172
196
|
|
173
197
|
def clean_mysql
|
174
198
|
Interaction.announce 'Checking for MySQL databases'
|
175
199
|
database_list = list_all_dbs('mysql')
|
176
|
-
# confirm_deletion includes option for
|
200
|
+
# confirm_deletion includes option for allowlist editing
|
177
201
|
deletable_dbs = confirm_deletion('mysql', database_list)
|
178
202
|
return if deletable_dbs.nil?
|
179
203
|
deletable_dbs.each do |db|
|
180
204
|
if @mysql_command.include? '-p'
|
181
|
-
|
205
|
+
Interaction.note "Please enter your MySQL/MariaDB account 'root' for: DROP DATABASE #{db}"
|
182
206
|
else
|
183
207
|
puts "Dropping MySQL/MariaDB database #{db}"
|
184
208
|
end
|
@@ -187,7 +211,7 @@ module Geordi
|
|
187
211
|
end
|
188
212
|
|
189
213
|
def clean_postgres
|
190
|
-
Interaction.announce 'Checking for
|
214
|
+
Interaction.announce 'Checking for PostgreSQL databases'
|
191
215
|
database_list = list_all_dbs('postgres')
|
192
216
|
deletable_dbs = confirm_deletion('postgres', database_list)
|
193
217
|
return if deletable_dbs.nil?
|
@@ -197,36 +221,36 @@ module Geordi
|
|
197
221
|
end
|
198
222
|
end
|
199
223
|
|
200
|
-
def
|
201
|
-
File.join(@
|
224
|
+
def allowlist_fname(dbtype)
|
225
|
+
File.join(@allowlist_directory, dbtype) << '.txt'
|
202
226
|
end
|
203
227
|
|
204
228
|
def confirm_deletion(dbtype, database_list)
|
205
229
|
proceed = ''
|
206
230
|
until %w[y n].include? proceed
|
207
|
-
deletable_dbs =
|
231
|
+
deletable_dbs = filter_allowlisted(dbtype, database_list)
|
208
232
|
if deletable_dbs.empty?
|
209
|
-
Interaction.note "No #{dbtype} databases found that were not
|
210
|
-
if Interaction.prompt('Edit the
|
233
|
+
Interaction.note "No #{dbtype} databases found that were not allowlisted."
|
234
|
+
if Interaction.prompt('Edit the allowlist? [y]es or [n]o') == 'y'
|
211
235
|
proceed = 'e'
|
212
236
|
else
|
213
237
|
return []
|
214
238
|
end
|
215
239
|
end
|
216
240
|
if proceed.empty?
|
217
|
-
Interaction.note "The following #{dbtype} databases are not
|
241
|
+
Interaction.note "The following #{dbtype} databases are not allowlisted and can be deleted:"
|
218
242
|
deletable_dbs.sort.each do |db|
|
219
243
|
puts db
|
220
244
|
end
|
221
|
-
Interaction.note "These #{dbtype} databases are not
|
222
|
-
proceed = Interaction.prompt('Proceed? [y]es, [n]o or [e]dit
|
245
|
+
Interaction.note "These #{dbtype} databases are not allowlisted and can be deleted."
|
246
|
+
proceed = Interaction.prompt('Proceed? [y]es, [n]o or [e]dit allowlist')
|
223
247
|
end
|
224
248
|
case proceed
|
225
249
|
when 'e'
|
226
250
|
proceed = '' # reset user selection
|
227
|
-
|
251
|
+
edit_allowlist dbtype
|
228
252
|
when 'n'
|
229
|
-
Interaction.
|
253
|
+
Interaction.note 'Nothing deleted.'
|
230
254
|
return []
|
231
255
|
when 'y'
|
232
256
|
return deletable_dbs
|
@@ -243,31 +267,49 @@ module Geordi
|
|
243
267
|
protected[dbtype].include? database_name
|
244
268
|
end
|
245
269
|
|
246
|
-
def
|
247
|
-
|
248
|
-
Geordi::Util.stripped_lines(File.open(
|
270
|
+
def is_allowlisted?(dbtype, database_name)
|
271
|
+
allowlist_content = if File.exist? allowlist_fname(dbtype)
|
272
|
+
Geordi::Util.stripped_lines(File.open(allowlist_fname(dbtype), 'r').read)
|
249
273
|
else
|
250
274
|
[]
|
251
275
|
end
|
252
|
-
# Allow explicit
|
253
|
-
if
|
276
|
+
# Allow explicit allowlisting of derivative databases like projectname_test2
|
277
|
+
if allowlist_content.include? database_name
|
254
278
|
true
|
255
|
-
#
|
256
|
-
elsif
|
279
|
+
# allowlisting `projectname` also allowlists `projectname_test\d*`, `projectname_development`
|
280
|
+
elsif allowlist_content.include? database_name.sub(@derivative_dbname, '')
|
257
281
|
true
|
258
282
|
else
|
259
283
|
false
|
260
284
|
end
|
261
285
|
end
|
262
286
|
|
263
|
-
def
|
287
|
+
def filter_allowlisted(dbtype, database_list)
|
264
288
|
# n.b. `delete` means 'delete from list of dbs that should be deleted in this context
|
265
289
|
# i.e. `delete` means 'keep this database'
|
266
290
|
deletable_dbs = database_list.dup
|
267
|
-
deletable_dbs.delete_if { |db|
|
291
|
+
deletable_dbs.delete_if { |db| is_allowlisted?(dbtype, db) if File.exist? allowlist_fname(dbtype) }
|
268
292
|
deletable_dbs.delete_if { |db| is_protected?(dbtype, db) }
|
269
293
|
deletable_dbs.delete_if { |db| db.start_with? '#' }
|
270
294
|
end
|
271
|
-
private :
|
295
|
+
private :filter_allowlisted
|
296
|
+
|
297
|
+
def legacy_allowlist_directory
|
298
|
+
@legacy_allowlist_directory ||= File.join(@base_directory, '.config', 'geordi', 'whitelists')
|
299
|
+
end
|
300
|
+
|
301
|
+
def move_allowlist_files
|
302
|
+
%w[postgres mysql].each do |dbtype|
|
303
|
+
new_path = allowlist_fname(dbtype)
|
304
|
+
next if File.exist?(new_path)
|
305
|
+
|
306
|
+
legacy_path = File.join(legacy_allowlist_directory, dbtype) << '.txt'
|
307
|
+
FileUtils.mv(legacy_path, new_path)
|
308
|
+
|
309
|
+
if Dir.exist?(legacy_allowlist_directory) && Dir.empty?(legacy_allowlist_directory)
|
310
|
+
Dir.delete(legacy_allowlist_directory)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
272
314
|
end
|
273
315
|
end
|
data/lib/geordi/dump_loader.rb
CHANGED
@@ -62,12 +62,16 @@ module Geordi
|
|
62
62
|
|
63
63
|
def postgresql_command
|
64
64
|
ENV['PGPASSWORD'] = config['password']
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
drop_command = 'dropdb --if-exists ' << config['database'].to_s
|
66
|
+
create_command = 'createdb ' << config['database'].to_s
|
67
|
+
restore_command = 'pg_restore --no-owner --no-acl'
|
68
|
+
restore_command << ' --username=' << config['username'].to_s if config['username']
|
69
|
+
restore_command << ' --port=' << config['port'].to_s if config['port']
|
70
|
+
restore_command << ' --host=' << config['host'].to_s if config['host']
|
71
|
+
restore_command << ' --dbname=' << config['database'].to_s
|
72
|
+
restore_command << ' ' << dump_file
|
73
|
+
|
74
|
+
drop_command + ' && ' + create_command + ' && ' + restore_command
|
71
75
|
end
|
72
76
|
|
73
77
|
def dump_file
|
data/lib/geordi/hint.rb
CHANGED
@@ -14,7 +14,7 @@ module Geordi
|
|
14
14
|
if generated_hints.any? && should_print_hint
|
15
15
|
puts
|
16
16
|
puts generated_hints.sample
|
17
|
-
puts
|
17
|
+
puts "You can configure the probability for these hints by setting hint_probability to a unitless percent number in #{Settings::GLOBAL_SETTINGS_FILE_NAME}" unless settings_probability
|
18
18
|
end
|
19
19
|
|
20
20
|
generated_hints
|
data/lib/geordi/settings.rb
CHANGED
@@ -8,7 +8,15 @@ module Geordi
|
|
8
8
|
GLOBAL_SETTINGS_FILE_NAME = Util.testing? ? './tmp/global_settings.yml'.freeze : File.join(ENV['HOME'], '.config/geordi/global.yml').freeze
|
9
9
|
LOCAL_SETTINGS_FILE_NAME = Util.testing? ? './tmp/local_settings.yml'.freeze : './.geordi.yml'.freeze
|
10
10
|
|
11
|
-
ALLOWED_GLOBAL_SETTINGS = %w[
|
11
|
+
ALLOWED_GLOBAL_SETTINGS = %w[
|
12
|
+
auto_update_chromedriver
|
13
|
+
git_initials
|
14
|
+
hint_probability
|
15
|
+
irb_flags
|
16
|
+
pivotal_tracker_api_key
|
17
|
+
pivotal_tracker_project_ids
|
18
|
+
].freeze
|
19
|
+
|
12
20
|
ALLOWED_LOCAL_SETTINGS = %w[ pivotal_tracker_project_ids ].freeze
|
13
21
|
|
14
22
|
SETTINGS_WARNED = 'GEORDI_INVALID_SETTINGS_WARNED'
|
@@ -18,6 +26,10 @@ module Geordi
|
|
18
26
|
end
|
19
27
|
|
20
28
|
# Global settings
|
29
|
+
def irb_flags
|
30
|
+
@global_settings['irb_flags']
|
31
|
+
end
|
32
|
+
|
21
33
|
def pivotal_tracker_api_key
|
22
34
|
@global_settings['pivotal_tracker_api_key'] || gitpt_api_key_old || inquire_pt_api_key
|
23
35
|
end
|
data/lib/geordi/util.rb
CHANGED
@@ -37,7 +37,8 @@ module Geordi
|
|
37
37
|
# show_cmd: Whether to print the command
|
38
38
|
# confirm: Whether to ask for confirmation before running it
|
39
39
|
# fail_message: The text to print on command failure
|
40
|
-
|
40
|
+
# exec: Whether to run the command with `exec` instead of `system`
|
41
|
+
def run!(command, show_cmd: false, confirm: false, fail_message: 'Something went wrong.', exec: false)
|
41
42
|
# Disable shell features for arrays https://stackoverflow.com/questions/13338147/ruby-system-method-arguments
|
42
43
|
# Conversion: ['ls *', 'some arg'] => ['ls', '*', 'some arg']
|
43
44
|
# If you need shell features, you need to pass in a String instead of an array.
|
@@ -60,19 +61,23 @@ module Geordi
|
|
60
61
|
|
61
62
|
if testing?
|
62
63
|
# Join with commas for precise argument distinction
|
63
|
-
puts "Util.run
|
64
|
+
puts "Util.run!#{' (exec)' if exec} #{show_command.join(', ')}"
|
64
65
|
else
|
66
|
+
method = exec ? :exec : :system
|
67
|
+
|
65
68
|
# Remove Geordi's Bundler environment when running commands.
|
66
69
|
success = if !defined?(Bundler)
|
67
|
-
|
70
|
+
Kernel.public_send(method, *command)
|
68
71
|
elsif Gem::Version.new(Bundler::VERSION) >= Gem::Version.new('1.17.3')
|
69
72
|
Bundler.with_original_env do
|
70
|
-
|
73
|
+
Kernel.public_send(method, *command)
|
71
74
|
end
|
72
75
|
else
|
73
|
-
|
76
|
+
method = exec ? :clean_exec : :clean_system
|
77
|
+
Bundler.public_send(method, *command)
|
74
78
|
end
|
75
79
|
|
80
|
+
# This part will never be reached when `exec` is true
|
76
81
|
success || Interaction.fail(fail_message)
|
77
82
|
end
|
78
83
|
end
|
@@ -89,14 +94,15 @@ module Geordi
|
|
89
94
|
elsif gem_major_version('rails') == 3
|
90
95
|
"#{binstub_or_fallback('rails')} console #{environment}"
|
91
96
|
else
|
92
|
-
|
93
|
-
|
94
|
-
|
97
|
+
use_multiline = if irb_version >= Gem::Version.new('1.2') && ruby_version < Gem::Version.new('3.0')
|
98
|
+
Interaction.note 'Using --nomultiline switch for faster pasting'
|
99
|
+
'--nomultiline'
|
100
|
+
end
|
101
|
+
|
102
|
+
irb_flags = [use_multiline, Settings.new.irb_flags].join(' ').strip
|
103
|
+
irb_flags.prepend('-- ') unless irb_flags.empty?
|
95
104
|
|
96
|
-
|
97
|
-
if irb_version >= Gem::Version.new('1.2') && ruby_version < Gem::Version.new('3.0')
|
98
|
-
Interaction.note 'Using --nomultiline switch for faster pasting'
|
99
|
-
'-- --nomultiline'
|
105
|
+
"#{binstub_or_fallback('rails')} console -e #{environment} #{irb_flags}"
|
100
106
|
end
|
101
107
|
end
|
102
108
|
|
@@ -193,7 +199,7 @@ module Geordi
|
|
193
199
|
version_string = if testing?
|
194
200
|
ENV['GEORDI_TESTING_IRB_VERSION']
|
195
201
|
else
|
196
|
-
`irb --version`[/irb (\d
|
202
|
+
`irb --version`[/irb (\d+\.\d+\.\d+)/, 1]
|
197
203
|
end
|
198
204
|
|
199
205
|
Gem::Version.new(version_string)
|
data/lib/geordi/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geordi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 10.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henning Koch
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -117,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
117
|
- !ruby/object:Gem::Version
|
118
118
|
version: '0'
|
119
119
|
requirements: []
|
120
|
-
rubygems_version: 3.
|
120
|
+
rubygems_version: 3.0.3
|
121
121
|
signing_key:
|
122
122
|
specification_version: 4
|
123
123
|
summary: Collection of command line tools we use in our daily work with Ruby, Rails
|