geordi 9.6.1 → 10.0.0
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 +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
|