geordi 9.0.0 → 9.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1060f10e77e6173a1b8d63fd8c2d89579e5be0597a683f5358b01173e4c266de
4
- data.tar.gz: 8a44e3cd313e779b84ae9ecfa0f92283f4dd3f45f7525ec0bc298b11a719c389
3
+ metadata.gz: e93051812acfd619f8d5a2db9c2641bb1ff19cf28835096cec1a2f6fd1487620
4
+ data.tar.gz: 4bc007b0985800b275de9dd0676cf0cbdf51a57800a4a426c0878738b9b00f43
5
5
  SHA512:
6
- metadata.gz: c7793fda9e1494d3b1a2cf50dfa7b8c10ff61e8c7462596828fe6e44721f50dedbfe18ba2a2c2fb4e0b354500de9528f6e948e8716c9c1a31ceb42a49c8ea845
7
- data.tar.gz: fedd7f3106bc5283b25b5f4e20fe1eda099d76c7e4b01483362cebde5cca516d559241d976ad51486a3bc71e11df5a3c21d14288c10805ad9af8307f48d7dab3
6
+ metadata.gz: 07105d522e4ed9c4412e95f0e8bd5dfbfbd4c8ea7bb7a58f7f347473eafb5807f7ceeaf82dc18f80dd85c77699970342f91396eec35f4a113a5aad8e0b73dc6d
7
+ data.tar.gz: 7bb8747a1352e983c3c3cecc848ae2097a01341e8c1bd0d1b32537e0470085d43cec4a639dbdc36eaacdd8fad5f4bce981032c8d06efe11c8ab0951afe4bbaec
data/CHANGELOG.md CHANGED
@@ -3,7 +3,6 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
5
5
 
6
-
7
6
  ## Unreleased
8
7
 
9
8
  ### Compatible changes
@@ -11,10 +10,30 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
11
10
  ### Breaking changes
12
11
 
13
12
 
13
+ ## 9.3.0 2022-04-26
14
+
15
+ ### Compatible changes
16
+ * Add dump loading in multi-database-setups.
17
+
18
+
19
+ ## 9.2.0 2022-02-18
20
+
21
+ ### Compatible changes
22
+ * Change the update mechanism of `geordi chromedriver-update`: This command (and `geordi cucumber`/`geordi tests` if the `auto_update_chromedriver` option is active) will now always update to the latest version of chromedriver for the current chrome version.
23
+
24
+
25
+ ## 9.1.0 2022-02-14
26
+
27
+ ### Compatible changes
28
+ * `geordi dump` and `dumple` now default to "primary" database or the first
29
+ entry in a multi-db setup
30
+ * Also added feature tests for `dumple` and structured the script
31
+
32
+
14
33
  ## 9.0.0 2021-12-02
15
34
 
16
35
  ### Breaking changes
17
- * Remove the `geordi docker` command.
36
+ * Remove the `geordi docker` command set.
18
37
 
19
38
 
20
39
  ## 8.0.0 2021-11-08
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- geordi (9.0.0)
4
+ geordi (9.3.0)
5
5
  thor (~> 1)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -53,10 +53,10 @@ installed Chrome.
53
53
 
54
54
  Setting `auto_update_chromedriver` to `true` in your global Geordi config file
55
55
  (`~/.config/geordi/global.yml`), will automatically update chromedriver before
56
- cucumber tests, in case Chrome and chromedriver versions don't match
56
+ cucumber tests if a newer chromedriver version is available.
57
57
 
58
58
  **Options**
59
- - `[--quiet-if-matching], [--no-quiet-if-matching]`: Suppress notification if chromedriver and chrome versions match
59
+ - `[--quiet-if-matching], [--no-quiet-if-matching]`: Suppress notification if chromedriver is already on the latest version
60
60
 
61
61
 
62
62
  ### `geordi clean`
@@ -194,15 +194,21 @@ specified target's database and downloads it to `tmp/`.
194
194
  `geordi dump staging -l` (with a Capistrano deploy target and the `--load`
195
195
  option) sources the dump into the development database after downloading it.
196
196
 
197
- If you are using multiple databases per environment, pass the database name like this:
197
+ If you are using multiple databases per environment, Geordi defaults to the
198
+ "primary" database, or the first entry in database.yml. To target a specific
199
+ database, pass the database name like this:
200
+ ```
201
+ geordi dump -d primary
202
+ ```
198
203
 
199
- geordi dump -d primary
200
-
201
- Loading a dump into one of multiple local databases is not supported yet.
204
+ When used with the blank `load` option ("dump and source"), the `database` option
205
+ will be respected both for the remote *and* the local database. If these should
206
+ not match, please issue separate commands for dumping (`dump -d`) and sourcing
207
+ (`dump -l -d`).
202
208
 
203
209
  **Options**
204
210
  - `-l, [--load=[DUMP_FILE]]`: Load a dump
205
- - `-d, [--database=NAME]`: Database name, if there are multiple databases
211
+ - `-d, [--database=NAME]`: Target database, if there are multiple databases
206
212
 
207
213
 
208
214
  ### `geordi help [COMMAND]`
data/exe/dumple CHANGED
@@ -1,28 +1,33 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'erb'
4
-
5
- fail_gently = ARGV.include?("--fail-gently")
6
- compress = ARGV.include?("--compress")
7
-
8
3
  if ARGV.include?("-i")
9
4
  puts "*******************************************************"
10
5
  puts
11
6
  system("du -sh ~/dumps")
12
7
  puts
13
8
  puts "*******************************************************"
9
+
14
10
  exit
15
11
  end
16
12
 
17
- ###
18
-
13
+ require 'erb'
19
14
  require "yaml"
20
- config_path = 'config/database.yml'
21
15
 
22
- begin
23
- # go to project root
16
+ DB_CONFIG_PATH = 'config/database.yml'
17
+ DUMPS_DIR = "#{ENV['HOME']}/dumps"
18
+
19
+ def run(*args)
20
+ if !!ENV['GEORDI_TESTING']
21
+ puts "system #{args.join(', ')}"
22
+ true # "Command succeeded"
23
+ else
24
+ system *args
25
+ end
26
+ end
27
+
28
+ def cd_to_project_root(fail_gently)
24
29
  current = Dir.pwd
25
- until (File.exists? config_path)
30
+ until File.exists?(DB_CONFIG_PATH)
26
31
  Dir.chdir '..'
27
32
  if current == Dir.pwd
28
33
  if fail_gently
@@ -38,46 +43,24 @@ begin
38
43
  sleep 5
39
44
  exit
40
45
  else
41
- raise "Call me from inside a Rails project."
46
+ raise "x Call me from inside a Rails project."
42
47
  end
43
48
  end
44
49
  current = Dir.pwd
45
50
  end
51
+ end
46
52
 
47
- config = YAML::load(ERB.new(File.read(config_path)).result)
48
- environment, database = ARGV.reject{ |arg| arg[0].chr == '-' }
49
- environment ||= 'production'
50
- config = config[environment] or raise "No #{environment} database found.\nUsage: dumple ENVIRONMENT [DATABASE]"
51
-
52
- if database
53
- config = config[database] or raise %(Unknown #{environment} database "#{database}")
54
- end
55
-
56
- dump_dir = "#{ENV['HOME']}/dumps"
57
- unless File.directory?(dump_dir)
58
- Dir.mkdir(dump_dir)
59
- system("chmod 700 #{dump_dir}")
60
- end
61
-
62
- if ARGV.find{ |arg| arg == '--for_download'}
63
- dump_path = "#{dump_dir}/dump_for_download.dump"
64
- else
65
- dump_path = "#{dump_dir}/#{config['database']}_#{Time.now.strftime("%Y%m%d_%H%M%S")}.dump"
66
- end
67
-
68
- given_database = database ? %(#{database} ) : ""
69
- puts "> Dumping #{given_database}database for \"#{environment}\" environment ..."
70
-
53
+ def dump_command(dump_file, config)
71
54
  host = config['host']
72
55
  port = config['port']
73
56
 
74
- dump_command = case config['adapter']
57
+ case config['adapter']
75
58
  when /mysql/
76
59
  command = "mysqldump"
77
60
  command << " -u\"#{config['username']}\""
78
61
  command << " -p\"#{config['password']}\""
79
62
  command << " #{config['database']}"
80
- command << " -r #{dump_path}"
63
+ command << " -r #{dump_file}"
81
64
  # Using a transaction to allow concurrent request while creating a dump.
82
65
  # This works only reliable for InnoDB tables.
83
66
  # More details: https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html#option_mysqldump_single-transaction
@@ -96,25 +79,75 @@ begin
96
79
  command << " pg_dump #{config['database']}"
97
80
  command << " --clean"
98
81
  command << " --format=custom"
99
- command << " --file=#{dump_path}"
82
+ command << " --file=#{dump_file}"
100
83
  command << " --username=\"#{config['username']}\""
101
84
  command << " --host=#{host}" if host
102
85
  command << " --port=#{port}" if port
103
86
  command
104
87
  else
105
- raise "Adapter \"#{config['adapter']}\" is not supported"
88
+ raise %(x Adapter "#{config['adapter']}" is not supported.)
89
+ end
90
+ end
91
+
92
+ def find_database_config(config_path, environment, database)
93
+ environment ||= 'production'
94
+ database_yml = ERB.new(File.read(config_path)).result
95
+ config = YAML::load(database_yml)
96
+ config = config[environment] or raise "x No #{environment} database found.\nUsage: dumple ENVIRONMENT [DATABASE]"
97
+
98
+ if config.values[0].is_a? Hash # Multi-db setup
99
+ if database # Explicitly requested
100
+ config = config[database] or raise %(x Unknown #{environment} database "#{database}".)
101
+ elsif config.key? 'primary'
102
+ puts '> Multiple databases detected. Defaulting to primary database.'
103
+ config = config['primary']
104
+ else
105
+ puts "> Multiple databases detected. Defaulting to first entry (#{config.keys[0]})."
106
+ config = config.values[0]
107
+ end
108
+ else # Single-db setup
109
+ if database
110
+ raise %(x Could not select "#{database}" database in a single-db environment.)
111
+ end
106
112
  end
107
- success = system(dump_command)
108
- success or raise "Creating the dump failed"
109
113
 
110
- system "chmod 600 #{dump_path}"
114
+ config
115
+ end
116
+
117
+ def prepare_dump_path(config)
118
+ unless File.directory?(DUMPS_DIR)
119
+ Dir.mkdir(DUMPS_DIR)
120
+ run "chmod 700 #{DUMPS_DIR}"
121
+ end
122
+
123
+ if ARGV.include? '--for_download'
124
+ "#{DUMPS_DIR}/dump_for_download.dump"
125
+ else
126
+ "#{DUMPS_DIR}/#{config['database']}_#{Time.now.strftime("%Y%m%d_%H%M%S")}.dump"
127
+ end
128
+ end
129
+
130
+ begin
131
+ fail_gently = ARGV.include?("--fail-gently")
132
+ compress = ARGV.include?("--compress")
133
+ environment, database = ARGV.reject { |arg| arg[0].chr == '-' }
134
+
135
+ cd_to_project_root(fail_gently)
136
+ config = find_database_config(DB_CONFIG_PATH, environment, database)
137
+ dump_path = prepare_dump_path(config)
138
+
139
+ # Dump!
140
+ given_database = database ? %(#{database} ) : ""
141
+ command = dump_command(dump_path, config)
142
+ puts "> Dumping #{given_database}database for \"#{environment}\" environment ..."
143
+ run command or raise "x Creating the dump failed."
144
+ run "chmod 600 #{dump_path}"
111
145
 
112
146
  if compress
113
147
  puts "> Compressing the dump ..."
114
-
115
148
  # gzip compresses in place
116
- compress_success = system("gzip #{dump_path}")
117
- compress_success or raise "Compressing the dump failed"
149
+ compress_success = run "gzip #{dump_path}"
150
+ compress_success or raise "x Compressing the dump failed."
118
151
  dump_path << ".gz"
119
152
  end
120
153
 
data/geordi.gemspec CHANGED
@@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.description = spec.summary
14
14
  spec.homepage = 'https://makandra.com'
15
15
  spec.license = 'MIT'
16
+ spec.metadata = { 'rubygems_mfa_required' => 'true' }
16
17
 
17
18
  # Specify which files should be added to the gem when it is released.
18
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -7,18 +7,13 @@ module Geordi
7
7
 
8
8
  def run(options)
9
9
  chrome_version = determine_chrome_version
10
- chromedriver_version = determine_chromedriver_version
10
+ current_chromedriver_version = determine_chromedriver_version
11
11
 
12
- if skip_update?(chrome_version, chromedriver_version)
13
- Interaction.success "No update required: both Chrome and chromedriver are on v#{chrome_version}!" unless options[:quiet_if_matching]
12
+ latest_chromedriver_version = latest_version(chrome_version)
13
+ if current_chromedriver_version == latest_chromedriver_version
14
+ Interaction.success "No update required: Chromedriver is already on the latest version v#{latest_chromedriver_version}!" unless options[:quiet_if_matching]
14
15
  else
15
- chromedriver_zip = download_chromedriver(chrome_version)
16
- unzip(chromedriver_zip, File.expand_path('~/bin'))
17
-
18
- chromedriver_zip.unlink
19
-
20
- # We need to determine the version again, as it could be nil in case no chromedriver was installed before
21
- Interaction.success "Chromedriver updated to v#{determine_chromedriver_version}."
16
+ update_chromedriver(latest_chromedriver_version)
22
17
  end
23
18
  end
24
19
 
@@ -27,13 +22,13 @@ module Geordi
27
22
  def determine_chrome_version
28
23
  stdout_str, _error_str, status = Open3.capture3('google-chrome', '--version')
29
24
  chrome_version = unless stdout_str.nil?
30
- stdout_str[/\AGoogle Chrome (\d+)/, 1]
25
+ stdout_str[/\AGoogle Chrome ([\d.]+)/, 1]
31
26
  end
32
27
 
33
28
  if !status.success? || chrome_version.nil?
34
29
  Interaction.fail('Could not determine the version of Google Chrome.')
35
30
  else
36
- chrome_version.to_i
31
+ chrome_version
37
32
  end
38
33
  end
39
34
 
@@ -42,23 +37,32 @@ module Geordi
42
37
 
43
38
  stdout_str, _error_str, status = Open3.capture3('chromedriver', '-v')
44
39
  chromedriver_version = unless stdout_str.nil?
45
- stdout_str[/\AChromeDriver (\d+)/, 1]
40
+ stdout_str[/\AChromeDriver ([\d.]+)/, 1]
46
41
  end
47
42
 
48
43
  if !status.success? || chromedriver_version.nil?
49
44
  Interaction.fail('Could not determine the version of chromedriver.')
50
45
  else
51
- chromedriver_version.to_i
46
+ chromedriver_version
52
47
  end
53
48
  end
54
49
 
55
- def skip_update?(chrome_version, chromedriver_version)
56
- chrome_version == chromedriver_version
50
+ # Check https://groups.google.com/a/chromium.org/g/chromium-discuss/c/4BB4jmsRyv8/m/TY3FXS4HBgAJ
51
+ # for information how chrome version numbers work
52
+ def major_version(full_version)
53
+ full_version.match(/^(\d+\.\d+\.\d+)\.\d+$/)[1]
57
54
  end
58
55
 
59
- def download_chromedriver(chrome_version)
60
- latest_version = latest_version(chrome_version)
56
+ def update_chromedriver(latest_chromedriver_version)
57
+ chromedriver_zip = download_chromedriver(latest_chromedriver_version)
58
+
59
+ unzip(chromedriver_zip, File.expand_path('~/bin'))
61
60
 
61
+ # We need to determine the version again, as it could be nil in case no chromedriver was installed before
62
+ Interaction.success "Chromedriver updated to v#{determine_chromedriver_version}."
63
+ end
64
+
65
+ def download_chromedriver(latest_version)
62
66
  uri = URI("https://chromedriver.storage.googleapis.com/#{latest_version}/chromedriver_linux64.zip")
63
67
  response = Net::HTTP.get_response(uri)
64
68
 
@@ -73,11 +77,13 @@ module Geordi
73
77
  end
74
78
 
75
79
  def latest_version(chrome_version)
76
- uri = URI("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_#{chrome_version}")
80
+ return @latest_version if @latest_version
81
+
82
+ uri = URI("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_#{major_version(chrome_version)}")
77
83
  response = Net::HTTP.get_response(uri)
78
84
 
79
85
  if response.is_a?(Net::HTTPSuccess)
80
- response.body.to_s
86
+ @latest_version = response.body.to_s
81
87
  else
82
88
  Interaction.fail("Could not download the chromedriver v#{chrome_version}.")
83
89
  end
@@ -7,11 +7,11 @@ installed Chrome.
7
7
 
8
8
  Setting `auto_update_chromedriver` to `true` in your global Geordi config file
9
9
  (`~/.config/geordi/global.yml`), will automatically update chromedriver before
10
- cucumber tests, in case Chrome and chromedriver versions don't match
10
+ cucumber tests if a newer chromedriver version is available.
11
11
  LONGDESC
12
12
 
13
13
  option :quiet_if_matching, type: :boolean, default: false,
14
- desc: 'Suppress notification if chromedriver and chrome versions match'
14
+ desc: 'Suppress notification if chromedriver is already on the latest version'
15
15
 
16
16
  def chromedriver_update
17
17
  require 'geordi/chromedriver_updater'
@@ -11,48 +11,53 @@ specified target's database and downloads it to `tmp/`.
11
11
  `geordi dump staging -l` (with a Capistrano deploy target and the `--load`
12
12
  option) sources the dump into the development database after downloading it.
13
13
 
14
- If you are using multiple databases per environment, pass the database name like this:
15
-
16
- geordi dump -d primary
17
-
18
- Loading a dump into one of multiple local databases is not supported yet.
14
+ If you are using multiple databases per environment, Geordi defaults to the
15
+ "primary" database, or the first entry in database.yml. To target a specific
16
+ database, pass the database name like this:
17
+ ```
18
+ geordi dump -d primary
19
+ ```
20
+
21
+ When used with the blank `load` option ("dump and source"), the `database` option
22
+ will be respected both for the remote *and* the local database. If these should
23
+ not match, please issue separate commands for dumping (`dump -d`) and sourcing
24
+ (`dump -l -d`).
19
25
  DESC
20
26
 
21
27
  option :load, aliases: '-l', type: :string, desc: 'Load a dump', banner: '[DUMP_FILE]'
22
- option :database, aliases: '-d', type: :string, desc: 'Database name, if there are multiple databases', banner: 'NAME'
28
+ option :database, aliases: '-d', type: :string, desc: 'Target database, if there are multiple databases', banner: 'NAME'
23
29
 
24
30
  def dump(target = nil, *_args)
25
31
  require 'geordi/dump_loader'
26
32
  require 'geordi/remote'
27
33
  database = options[:database] ? "#{options[:database]} " : ''
28
34
 
29
- if target.nil?
30
- if options.load
31
- # validate load option
35
+ if target.nil? # Local …
36
+ if options.load # … dump loading
32
37
  Interaction.fail 'Missing a dump file.' if options.load == 'load'
33
38
  File.exist?(options.load) || raise('Could not find the given dump file: ' + options.load)
34
39
 
35
- loader = DumpLoader.new(options.load)
40
+ loader = DumpLoader.new(options.load, options.database)
36
41
 
37
42
  Interaction.announce "Sourcing dump into the #{loader.config['database']} db"
38
43
  loader.load
39
44
 
40
45
  Interaction.success "Your #{loader.config['database']} database has now the data of #{options.load}."
41
46
 
42
- else
47
+ else # … dump creation
43
48
  Interaction.announce 'Dumping the development database'
44
49
  Util.run!("dumple development #{database}")
45
50
  Interaction.success "Successfully dumped the #{database}development database."
46
51
  end
47
52
 
48
- else
53
+ else # Remote dumping …
49
54
  database_label = options[:database] ? " (#{database}database)" : ""
50
55
 
51
56
  Interaction.announce "Dumping the database of #{target}#{database_label}"
52
57
  dump_path = Geordi::Remote.new(target).dump(options)
53
58
 
54
- if options.load
55
- loader = DumpLoader.new(dump_path)
59
+ if options.load # … and dump loading
60
+ loader = DumpLoader.new(dump_path, options.database)
56
61
 
57
62
  Interaction.announce "Sourcing dump into the #{loader.config['database']} db"
58
63
  loader.load
@@ -6,24 +6,45 @@ require 'geordi/util'
6
6
  module Geordi
7
7
  class DumpLoader
8
8
 
9
- def initialize(file)
9
+ def initialize(file, database)
10
10
  @dump_file = file
11
+ @database = database
11
12
  end
12
13
 
13
14
  def development_database_config
15
+ return @config if @config
16
+
14
17
  require 'yaml'
15
18
 
16
19
  evaluated_config_file = ERB.new(File.read('config/database.yml')).result
17
20
 
18
21
  # Allow aliases and a special set of classes like symbols and time objects
19
22
  permitted_classes = [Symbol, Time]
20
- @config ||= if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0')
23
+ database_config = if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0')
21
24
  YAML.safe_load(evaluated_config_file, permitted_classes: permitted_classes, aliases: true)
22
25
  else
23
26
  YAML.safe_load(evaluated_config_file, permitted_classes, [], true)
24
27
  end
25
28
 
26
- @config['development']
29
+ development_config = database_config['development']
30
+
31
+ if development_config.values[0].is_a? Hash # Multi-db setup
32
+ @config = if @database
33
+ development_config[@database] || Interaction.fail(%(Unknown development database "#{@database}".))
34
+ elsif development_config.has_key? 'primary'
35
+ development_config['primary']
36
+ else
37
+ development_config.values[0]
38
+ end
39
+ else # Single-db setup
40
+ if @database
41
+ Interaction.fail %(Could not select "#{@database}" database in a single-db setup.)
42
+ else
43
+ @config = development_config
44
+ end
45
+ end
46
+
47
+ @config
27
48
  end
28
49
  alias_method :config, :development_database_config
29
50
 
@@ -61,9 +82,12 @@ module Geordi
61
82
  end
62
83
 
63
84
  def load
85
+ adapter_command = "#{config['adapter']}_command"
86
+ Interaction.fail "Unknown database adapter #{config['adapter'].inspect} in config/database.yml." unless respond_to? adapter_command
87
+
64
88
  Interaction.note 'Source file: ' + dump_file
65
89
 
66
- source_command = send("#{config['adapter']}_command")
90
+ source_command = send(adapter_command)
67
91
  Util.run! source_command, fail_message: "An error occurred loading #{File.basename(dump_file)}"
68
92
  end
69
93
 
@@ -1,3 +1,3 @@
1
1
  module Geordi
2
- VERSION = '9.0.0'.freeze
2
+ VERSION = '9.3.0'.freeze
3
3
  end
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: 9.0.0
4
+ version: 9.3.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: 2021-12-02 00:00:00.000000000 Z
11
+ date: 2022-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -96,11 +96,12 @@ files:
96
96
  homepage: https://makandra.com
97
97
  licenses:
98
98
  - MIT
99
- metadata: {}
99
+ metadata:
100
+ rubygems_mfa_required: 'true'
100
101
  post_install_message: 'Support for sequential running of integration tests tagged
101
102
  with @solo has been dropped.
102
103
 
103
- '
104
+ '
104
105
  rdoc_options: []
105
106
  require_paths:
106
107
  - lib
@@ -115,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
116
  - !ruby/object:Gem::Version
116
117
  version: '0'
117
118
  requirements: []
118
- rubygems_version: 3.2.32
119
+ rubygems_version: 3.2.30
119
120
  signing_key:
120
121
  specification_version: 4
121
122
  summary: Collection of command line tools we use in our daily work with Ruby, Rails