busser 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/publish.yml +22 -0
  3. data/.release-please-manifest.json +1 -1
  4. data/.rubocop.yml +1 -4
  5. data/CHANGELOG.md +18 -0
  6. data/Gemfile +12 -5
  7. data/README.md +82 -0
  8. data/Rakefile +19 -1
  9. data/busser.gemspec +11 -8
  10. data/features/plugin_create_command.feature +7 -9
  11. data/lib/busser/command/deserialize.rb +4 -0
  12. data/lib/busser/command/plugin_create.rb +46 -3
  13. data/lib/busser/command/plugin_install.rb +40 -4
  14. data/lib/busser/command/plugin_list.rb +16 -4
  15. data/lib/busser/command/setup.rb +37 -3
  16. data/lib/busser/command/suite_cleanup.rb +3 -0
  17. data/lib/busser/command/suite_path.rb +3 -0
  18. data/lib/busser/command/test.rb +38 -1
  19. data/lib/busser/cucumber/hooks.rb +9 -0
  20. data/lib/busser/helpers.rb +24 -0
  21. data/lib/busser/plugin.rb +51 -9
  22. data/lib/busser/rubygems.rb +20 -0
  23. data/lib/busser/runner_plugin/dummy.rb +3 -0
  24. data/lib/busser/runner_plugin.rb +5 -0
  25. data/lib/busser/thor.rb +23 -0
  26. data/lib/busser/ui.rb +63 -0
  27. data/lib/busser/version.rb +2 -1
  28. data/release-please-config.json +3 -1
  29. data/spec/busser/command/deserialize_spec.rb +0 -1
  30. data/spec/busser/command/plugin_create_spec.rb +174 -0
  31. data/spec/busser/command/plugin_install_spec.rb +44 -0
  32. data/spec/busser/command/plugin_list_spec.rb +49 -0
  33. data/spec/busser/command/setup_spec.rb +120 -0
  34. data/spec/busser/command/test_spec.rb +36 -0
  35. data/spec/busser/helpers_spec.rb +10 -10
  36. data/spec/busser/plugin_spec.rb +0 -1
  37. data/spec/busser/ui_spec.rb +56 -10
  38. data/spec/spec_helper.rb +2 -3
  39. data/templates/plugin/Rakefile.erb +4 -24
  40. data/templates/plugin/features_env.rb.erb +4 -4
  41. data/templates/plugin/gemspec.erb +7 -8
  42. data/templates/plugin/github_workflow.yml.erb +26 -0
  43. metadata +13 -60
  44. data/templates/plugin/tailor.erb +0 -4
  45. data/templates/plugin/travis.yml.erb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a59df776e51a951b813e8427048a91915f8a51488899ea85ed38e244704f7fc4
4
- data.tar.gz: 4fa1ecc9d303f82f4a26629993229a7a82c46edd1d1f14a77c544689b7e8642a
3
+ metadata.gz: cdaf83b2875620df49aa36203b6d4f7f2f6af8065ecbaa218705c949fa96fe04
4
+ data.tar.gz: 40471ed874096d5b55bb8c613a33a7729e761d691f6727e4a848edf0fe398dbd
5
5
  SHA512:
6
- metadata.gz: 18e4d5ef6b17149137cade75655c0406194ad432fbb14835a0ce05cd8e32bf0b60c8fa00f2dc4a7015990110972284d23b24488324fcd5af1cce5f445b0806e7
7
- data.tar.gz: 8bc4b488740a43e4a28a40edf93f0b021fbac496f2edaee2df43f0eb898f708b447b69f14e72498d9d46ffb7b34821d2f1a1f25fae4373c9b62d76cb8e85e84f
6
+ metadata.gz: 01b77c64592e8bed4f630149be35b89e5b3ac9935119f0c62216b5c16c0ae32ef3feb75c61d68ddf1127ea7bafff7de31f5d11297f2498501d9641b74eab163d
7
+ data.tar.gz: 8efbe414c2a434a98ff91be2f368bd2811cf8110bfce65c337859fbe3806ddca29751f9969a1fa9718c75b8ced4b92176ee33b137bf93b2046cace29fe77f0f6
@@ -43,3 +43,25 @@ jobs:
43
43
  uses: actionshub/publish-gem-to-rubygems@f9126f7a2d36a4fd31a13e78fde5fbdcc4b7b251 # v2.0.6
44
44
  with:
45
45
  token: ${{ secrets.RUBYGEMS_API_KEY }}
46
+
47
+ # actionshub/publish-gem-to-rubygems logs a rejected push and still exits
48
+ # 0, so a release that never reached RubyGems shows up as a green job.
49
+ # Ask RubyGems directly instead of trusting the step. The v2 endpoint is
50
+ # 404 until the exact version is indexed, so -f turns "not there" into a
51
+ # non-zero exit rather than a substring match on `gem list` output.
52
+ - name: Verify the release reached RubyGems
53
+ if: ${{ steps.release.outputs.release_created }}
54
+ env:
55
+ VERSION: ${{ steps.release.outputs.version }}
56
+ run: |
57
+ set -euo pipefail
58
+ name="$(basename "$(ls ./*.gemspec)" .gemspec)"
59
+ for _ in $(seq 1 12); do
60
+ if curl -fsS -o /dev/null "https://rubygems.org/api/v2/rubygems/${name}/versions/${VERSION}.json"; then
61
+ echo "${name} ${VERSION} is on RubyGems"
62
+ exit 0
63
+ fi
64
+ sleep 15
65
+ done
66
+ echo "::error::${name} ${VERSION} never reached RubyGems. A permissions failure in the push step above does not fail that step -- read its log."
67
+ exit 1
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.9.0"
2
+ ".": "0.9.2"
3
3
  }
data/.rubocop.yml CHANGED
@@ -3,7 +3,4 @@ require:
3
3
  - cookstyle/chefstyle
4
4
 
5
5
  AllCops:
6
- TargetRubyVersion: 3.1
7
- Exclude:
8
- - "vendor/**/*"
9
- - "spec/**/*"
6
+ TargetRubyVersion: 3.2
data/CHANGELOG.md CHANGED
@@ -33,6 +33,24 @@ main reason to take this version.
33
33
  * Rewritten README, and development documentation moved to
34
34
  CONTRIBUTING.md ([#63](https://github.com/test-kitchen/busser/pull/63))
35
35
 
36
+ ## [0.9.2](https://github.com/test-kitchen/busser/compare/v0.9.1...v0.9.2) (2026-08-28)
37
+
38
+
39
+ ### Bug Fixes
40
+
41
+ * quote the prepare.sh path before handing it to a shell ([#73](https://github.com/test-kitchen/busser/issues/73)) ([00a24a4](https://github.com/test-kitchen/busser/commit/00a24a4d4c286f50ac698b2cda9e9600b1c54322))
42
+ * restore SSL verification if a plugin postinstall raises ([#72](https://github.com/test-kitchen/busser/issues/72)) ([7f26adb](https://github.com/test-kitchen/busser/commit/7f26adbca1682bd152afb8fc15d90feb55c15d8e))
43
+ * stop `busser plugin list` printing git errors and a phantom plugin ([#77](https://github.com/test-kitchen/busser/issues/77)) ([7a99ebd](https://github.com/test-kitchen/busser/commit/7a99ebd8453ddc836bc0abf0af0f639f07b8d554))
44
+ * tell Thor to exit non-zero when a command fails ([#76](https://github.com/test-kitchen/busser/issues/76)) ([218ba31](https://github.com/test-kitchen/busser/commit/218ba31b812db55cba2479ba6345d305743cb0c1))
45
+
46
+ ## [0.9.1](https://github.com/test-kitchen/busser/compare/v0.9.0...v0.9.1) (2026-08-28)
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * generate a plugin project that resolves and builds ([#68](https://github.com/test-kitchen/busser/issues/68)) ([0c9a450](https://github.com/test-kitchen/busser/commit/0c9a450af83f086ac3627be938db856c9657208b))
52
+ * report signals and keep bundler out of the busser binstub ([#66](https://github.com/test-kitchen/busser/issues/66)) ([4fc9b35](https://github.com/test-kitchen/busser/commit/4fc9b350c7e3990c82ce4e229927be60a6431ee7))
53
+
36
54
  ## 0.8.0 / 2020-08-20
37
55
 
38
56
  - Add http_proxy support to `busser plugin install`
data/Gemfile CHANGED
@@ -1,13 +1,20 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gemspec development_group: :test
3
+ gemspec
4
+
4
5
  group :cookstyle do
5
- gem "cookstyle"
6
+ gem "cookstyle", ">= 9.0"
6
7
  end
7
8
 
8
9
  group :test do
9
- gem "minitest", ">= 6.0"
10
- gem "base64" # cucumber needs it; not a default gem on Ruby 4.0
10
+ gem "aruba", ">= 2.4"
11
+ gem "base64", ">= 0.3" # cucumber needs it; not a default gem on Ruby 4.0
11
12
  gem "cucumber", ">= 11.1"
12
- gem "rake"
13
+ gem "minitest", ">= 6.0"
14
+ gem "mocha", ">= 2.7"
15
+ gem "rake", ">= 13.4"
16
+ end
17
+
18
+ group :development do
19
+ gem "yard", ">= 0.9.37"
13
20
  end
data/README.md CHANGED
@@ -87,6 +87,88 @@ busser test
87
87
  busser test bash minitest
88
88
  ```
89
89
 
90
+ ## Using Busser with Test Kitchen
91
+
92
+ This is how most people meet Busser, and it needs no `busser` commands of your
93
+ own. Select the verifier in `kitchen.yml`:
94
+
95
+ ```yaml
96
+ verifier:
97
+ name: busser
98
+
99
+ suites:
100
+ - name: default
101
+ ```
102
+
103
+ Then put tests in a directory named after the plugin that should run them,
104
+ inside the suite:
105
+
106
+ ```text
107
+ test/integration/default/bash/smoke_test.sh
108
+ ```
109
+
110
+ `kitchen verify` installs Busser and the matching plugin on the instance, then
111
+ runs the suite. Which plugin runs is decided by that directory name alone --
112
+ `bash/` is picked up by busser-bash, `minitest/` by busser-minitest, and so on.
113
+ There is nothing else to configure.
114
+
115
+ ## A worked example, without Test Kitchen
116
+
117
+ To see Busser on its own, set a `BUSSER_ROOT` you can write to:
118
+
119
+ ```bash
120
+ export BUSSER_ROOT=/tmp/busser
121
+ busser setup
122
+ busser plugin install busser-bash
123
+ mkdir -p "$BUSSER_ROOT/suites/bash"
124
+
125
+ cat > "$BUSSER_ROOT/suites/bash/smoke_test.sh" <<'SH'
126
+ #!/usr/bin/env bash
127
+ set -euo pipefail
128
+ echo hello
129
+ SH
130
+
131
+ busser test bash
132
+ ```
133
+
134
+ A passing run looks like this, and exits `0`:
135
+
136
+ ```text
137
+ -----> Running bash test suite
138
+ -----> [bash] smoke_test.sh
139
+ hello
140
+ ```
141
+
142
+ A failing one names the command and exits non-zero:
143
+
144
+ ```text
145
+ -----> Running bash test suite
146
+ -----> [bash] smoke_test.sh
147
+ !!!!!! Command [bash /tmp/busser/suites/bash/smoke_test.sh] exit code was 1
148
+ ```
149
+
150
+ ## When nothing runs
151
+
152
+ A suite whose files do not match what the plugin looks for produces this, and
153
+ **exits `0`**:
154
+
155
+ ```text
156
+ -----> Running bash test suite
157
+ ```
158
+
159
+ No tests ran, and nothing said so. If a suite looks like it is being skipped,
160
+ work through these in order:
161
+
162
+ 1. **Is the plugin installed?** `busser plugin list` shows what is available.
163
+ Without the plugin, `busser test` has no runner for that directory.
164
+ 2. **Is the directory named after the plugin?** Tests for busser-bash live in
165
+ `bash/`, not `tests/` or `scripts/`.
166
+ 3. **Do the filenames match?** Each plugin globs for its own pattern -- for
167
+ example busser-bash takes `*_test.sh` and `*_spec.bash` but ignores
168
+ `mytest.sh`. Each plugin's README states its pattern.
169
+ 4. **Is `BUSSER_ROOT` what you think?** `busser suite path` prints where suites
170
+ are actually being looked for.
171
+
90
172
  ## Contributing
91
173
 
92
174
  Bug reports and pull requests are welcome. See
data/Rakefile CHANGED
@@ -9,7 +9,25 @@ Rake::TestTask.new(:unit) do |t|
9
9
  end
10
10
 
11
11
  Cucumber::Rake::Task.new(:features) do |t|
12
- t.cucumber_opts = ["features", "-x", "--format progress", "--no-color", "-b"]
12
+ t.cucumber_opts = ["features", "--format progress", "--fail-fast"]
13
+ end
14
+
15
+ # yard lives in the :development group, which CI omits when it runs the tests.
16
+ # Requiring it unconditionally would make `rake test` fail there, so the real
17
+ # task is only defined when yard is installed and a stub explains its absence
18
+ # otherwise. Nothing in CI gates on documentation.
19
+ begin
20
+ require "yard"
21
+
22
+ YARD::Rake::YardocTask.new(:doc) do |t|
23
+ t.files = ["lib/**/*.rb"]
24
+ t.options = ["--output-dir", "doc", "--markup", "markdown"]
25
+ end
26
+ rescue LoadError
27
+ desc "Generate YARD documentation (install the development group first)"
28
+ task :doc do
29
+ abort "yard is not available. Run `bundle install --with development` first."
30
+ end
13
31
  end
14
32
 
15
33
  desc "Run all test suites"
data/busser.gemspec CHANGED
@@ -7,25 +7,28 @@ Gem::Specification.new do |spec|
7
7
  spec.version = Busser::VERSION
8
8
  spec.authors = ["Fletcher Nichol"]
9
9
  spec.email = ["fnichol@nichol.ca"]
10
- spec.description = %q{Busser - Runs tests for projects in Test Kitchen}
10
+ spec.description = "Busser - Runs tests for projects in Test Kitchen"
11
11
  spec.summary = spec.description
12
12
  spec.homepage = "https://github.com/test-kitchen/busser"
13
13
  spec.license = "Apache-2.0"
14
14
 
15
- spec.files = `git ls-files`.split($/)
15
+ spec.required_ruby_version = ">= 3.2"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
16
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
19
  spec.require_paths = ["lib"]
18
20
 
19
- spec.required_ruby_version = ">= 3.2"
21
+ spec.metadata = {
22
+ "bug_tracker_uri" => "#{spec.homepage}/issues",
23
+ "changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md",
24
+ "documentation_uri" => "#{spec.homepage}/blob/main/README.md",
25
+ "homepage_uri" => spec.homepage,
26
+ "source_code_uri" => spec.homepage,
27
+ }
20
28
 
21
29
  # thor 1.1.0 references DidYouMean::SPELL_CHECKERS, removed in Ruby 3.1,
22
30
  # so the CLI crashed on startup on every supported Ruby
23
31
  spec.add_dependency "thor", ">= 1.1"
24
32
  # base64 is no longer a default gem; deserialize needs it at runtime
25
33
  spec.add_dependency "base64"
26
-
27
- spec.add_development_dependency "aruba", ">= 2.0"
28
- spec.add_development_dependency "minitest"
29
- spec.add_development_dependency "mocha"
30
- spec.add_development_dependency "rake"
31
34
  end
@@ -11,7 +11,7 @@ Feature: Plugin create command
11
11
  ## 0.1.0 / Unreleased
12
12
  """
13
13
  And the file "busser-junit/Gemfile" should contain "gemspec"
14
- And the file "busser-junit/Rakefile" should contain "task :stats"
14
+ And the file "busser-junit/Rakefile" should contain "Cucumber::Rake::Task"
15
15
  And the file "busser-junit/README.md" should contain:
16
16
  """
17
17
  Busser::RunnerPlugin::Junit
@@ -28,15 +28,13 @@ Feature: Plugin create command
28
28
  """
29
29
  Gemfile.lock
30
30
  """
31
- And the file "busser-junit/.tailor" should contain:
31
+ And the file "busser-junit/.github/workflows/test.yml" should contain:
32
32
  """
33
- config.file_set 'lib/**/*.rb'
33
+ bundle exec rake test
34
34
  """
35
- And the file "busser-junit/.travis.yml" should contain:
36
- """
37
- language: ruby
38
- """
39
- And a file named "busser-junit/.cane" should exist
35
+ And a file named "busser-junit/.travis.yml" should not exist
36
+ And a file named "busser-junit/.tailor" should not exist
37
+ And a file named "busser-junit/.cane" should not exist
40
38
  And the file "busser-junit/lib/busser/junit/version.rb" should contain:
41
39
  """
42
40
  module Busser
@@ -49,7 +47,7 @@ Feature: Plugin create command
49
47
  """
50
48
  And the file "busser-junit/features/support/env.rb" should contain:
51
49
  """
52
- require 'busser/cucumber'
50
+ require "busser/cucumber"
53
51
  """
54
52
  And the file "busser-junit/features/plugin_install_command.feature" should contain:
55
53
  """
@@ -38,6 +38,10 @@ module Busser
38
38
 
39
39
  class_option :perms, desc: "Unix permissions on destination file"
40
40
 
41
+ # Writes a file that was streamed in over stdin, checking it arrived
42
+ # intact before applying its permissions.
43
+ #
44
+ # @return [void]
41
45
  def perform
42
46
  file = File.expand_path(options[:destination])
43
47
  contents = Base64.decode64(STDIN.read)
@@ -36,6 +36,9 @@ module Busser
36
36
  class_option :license, aliases: "-l", default: "apachev2",
37
37
  desc: "License type for gem (apachev2, mit, lgplv3, reserved)"
38
38
 
39
+ # Generates a new runner plugin project.
40
+ #
41
+ # @return [void]
39
42
  def create
40
43
  self.class.source_root(Busser.source_root.join("templates", "plugin"))
41
44
 
@@ -47,6 +50,9 @@ module Busser
47
50
 
48
51
  private
49
52
 
53
+ # Writes the gemspec, Gemfile, Rakefile, README and licence.
54
+ #
55
+ # @return [void]
50
56
  def create_core_files
51
57
  empty_directory(target_dir)
52
58
 
@@ -57,11 +63,12 @@ module Busser
57
63
  create_template("gemspec.erb", "#{config[:gem_name]}.gemspec")
58
64
  create_template("license_#{config[:license]}.erb", license_filename)
59
65
  create_template("gitignore.erb", ".gitignore")
60
- create_template("tailor.erb", ".tailor")
61
- create_template("travis.yml.erb", ".travis.yml")
62
- create_file(File.join(target_dir, ".cane"))
66
+ create_template("github_workflow.yml.erb", ".github/workflows/test.yml")
63
67
  end
64
68
 
69
+ # Writes lib/, the version file and the runner plugin class.
70
+ #
71
+ # @return [void]
65
72
  def create_source_files
66
73
  empty_directory(File.join(target_dir, "lib/busser", name))
67
74
  empty_directory(File.join(target_dir, "lib/busser/runner_plugin"))
@@ -76,6 +83,9 @@ module Busser
76
83
  )
77
84
  end
78
85
 
86
+ # Writes a starter cucumber suite for the new plugin.
87
+ #
88
+ # @return [void]
79
89
  def create_features_files
80
90
  empty_directory(File.join(target_dir, "features/support"))
81
91
 
@@ -97,6 +107,10 @@ module Busser
97
107
  )
98
108
  end
99
109
 
110
+ # Runs git init in the generated project, so the gemspec's
111
+ # `git ls-files` has something to read.
112
+ #
113
+ # @return [void]
100
114
  def initialize_git
101
115
  inside(target_dir) do
102
116
  run("git init")
@@ -104,14 +118,21 @@ module Busser
104
118
  end
105
119
  end
106
120
 
121
+ # @param erb [String] template path, relative to the templates directory
122
+ # @param dest [String] destination path, relative to the target directory
123
+ # @return [void]
107
124
  def create_template(erb, dest)
108
125
  template(erb, File.join(target_dir, dest), config)
109
126
  end
110
127
 
128
+ # @return [String] directory the new plugin is generated into
111
129
  def target_dir
112
130
  File.join(Dir.pwd, "busser-#{name}")
113
131
  end
114
132
 
133
+ # Values the templates interpolate.
134
+ #
135
+ # @return [Hash] the template binding
115
136
  def config
116
137
  @config ||= begin
117
138
  type_klass_name = "#{::Thor::Util.camel_case(options[:type])}Plugin"
@@ -128,21 +149,25 @@ module Busser
128
149
  email: email,
129
150
  license: options[:license],
130
151
  license_string: license_string,
152
+ license_spdx: license_spdx,
131
153
  year: Time.now.year,
132
154
  }
133
155
  end
134
156
  end
135
157
 
158
+ # @return [String] the author name, from git config where available
136
159
  def author
137
160
  git_user_name = `git config user.name`.chomp
138
161
  git_user_name.empty? ? "TODO: Write your name" : git_user_name
139
162
  end
140
163
 
164
+ # @return [String] the author email, from git config where available
141
165
  def email
142
166
  git_user_email = `git config user.email`.chomp
143
167
  git_user_email.empty? ? "TODO: Write your email" : git_user_email
144
168
  end
145
169
 
170
+ # @return [String] full licence text for the chosen licence
146
171
  def license_string
147
172
  case options[:license]
148
173
  when "mit" then "MIT"
@@ -154,6 +179,23 @@ module Busser
154
179
  end
155
180
  end
156
181
 
182
+ # RubyGems validates spec.license against the SPDX list and warns on
183
+ # anything else, so the gemspec cannot reuse the human readable name
184
+ # that the README wants. "All rights reserved" has no SPDX identifier,
185
+ # so those gemspecs declare no license at all.
186
+ def license_spdx
187
+ case options[:license]
188
+ when "mit" then "MIT"
189
+ when "apachev2" then "Apache-2.0"
190
+ when "lgplv3" then "LGPL-3.0-only"
191
+ when "reserved" then nil
192
+ else
193
+ raise ArgumentError, "No such license #{options[:license]}"
194
+ end
195
+ end
196
+
197
+ # @return [String] the filename the licence is written to, which differs
198
+ # by licence
157
199
  def license_filename
158
200
  case options[:license]
159
201
  when "mit" then "LICENSE.txt"
@@ -164,6 +206,7 @@ module Busser
164
206
  end
165
207
  end
166
208
 
209
+ # @return [String] the licence header comment prepended to source files
167
210
  def license_comment
168
211
  @license_comment ||= IO.read(File.join(target_dir, license_filename))
169
212
  .gsub(/^/, "# ").gsub(/\s+$/, "")
@@ -40,6 +40,9 @@ module Busser
40
40
  class_option :verbose, type: :boolean, default: false,
41
41
  desc: "Set a more verbose output"
42
42
 
43
+ # Installs each requested plugin.
44
+ #
45
+ # @return [void]
43
46
  def install_all
44
47
  if options[:verbose]
45
48
  Gem.configuration.verbose = 2 if options[:verbose]
@@ -53,6 +56,10 @@ module Busser
53
56
 
54
57
  private
55
58
 
59
+ # Installs one plugin and runs its postinstall.
60
+ #
61
+ # @param plugin [String] gem name, optionally suffixed with @version
62
+ # @return [void]
56
63
  def install(plugin)
57
64
  gem_name, version = plugin.split("@")
58
65
  name = gem_name.sub(/^busser-/, "")
@@ -65,6 +72,12 @@ module Busser
65
72
  end
66
73
  end
67
74
 
75
+ # Installs the plugin gem unless it is already available.
76
+ #
77
+ # @param gem [String] the gem name
78
+ # @param version [String, nil] a version requirement, or nil for any
79
+ # @param name [String] short plugin name, for the message
80
+ # @return [Boolean] true if the gem was newly installed
68
81
  def install_plugin_gem(gem, version, name)
69
82
  if internal_plugin?(name) || gem_installed?(gem, version)
70
83
  info "Plugin #{name} already installed"
@@ -76,10 +89,17 @@ module Busser
76
89
  end
77
90
  end
78
91
 
92
+ # @param name [String] short plugin name
93
+ # @return [void]
79
94
  def load_plugin(name)
80
95
  Busser::Plugin.require!(Busser::Plugin.runner_plugin(name))
81
96
  end
82
97
 
98
+ # Runs the plugin's postinstall block, which is where a plugin installs
99
+ # the test framework it drives.
100
+ #
101
+ # @param name [String] short plugin name
102
+ # @return [void]
83
103
  def run_postinstall(name)
84
104
  klass = Busser::Plugin.runner_class(::Thor::Util.camel_case(name))
85
105
  if klass.respond_to?(:run_postinstall)
@@ -100,13 +120,29 @@ module Busser
100
120
  #
101
121
  # Please use with extreme caution.
102
122
  #
123
+ # The restore is in an ensure block. Without one, a postinstall that
124
+ # raised left VERIFY_PEER set to VERIFY_NONE for the rest of the
125
+ # process -- and `busser plugin install` takes a list, so every gem
126
+ # downloaded for every later plugin in that same run would have had its
127
+ # certificate unchecked.
128
+ #
129
+ # @yield the block to run with peer verification dropped
130
+ # @return [void]
103
131
  def drop_ssl_verify_peer
104
132
  before = OpenSSL::SSL::VERIFY_PEER
133
+ set_ssl_verify_peer(OpenSSL::SSL::VERIFY_NONE)
134
+ begin
135
+ yield
136
+ ensure
137
+ set_ssl_verify_peer(before)
138
+ end
139
+ end
140
+
141
+ # @param value [Integer] the OpenSSL verify mode to install
142
+ # @return [void]
143
+ def set_ssl_verify_peer(value)
105
144
  OpenSSL::SSL.send(:remove_const, "VERIFY_PEER")
106
- OpenSSL::SSL.const_set("VERIFY_PEER", OpenSSL::SSL::VERIFY_NONE)
107
- yield
108
- OpenSSL::SSL.send(:remove_const, "VERIFY_PEER")
109
- OpenSSL::SSL.const_set("VERIFY_PEER", before)
145
+ OpenSSL::SSL.const_set("VERIFY_PEER", value)
110
146
  end
111
147
  end
112
148
  end
@@ -28,6 +28,9 @@ module Busser
28
28
  #
29
29
  class PluginList < Busser::Thor::BaseGroup
30
30
 
31
+ # Prints the installed plugins and their versions.
32
+ #
33
+ # @return [void]
31
34
  def list
32
35
  if plugin_data.empty?
33
36
  say "No plugins installed yet"
@@ -38,11 +41,20 @@ module Busser
38
41
 
39
42
  private
40
43
 
44
+ # The dummy runner is a fixture shipped inside busser for its own tests,
45
+ # not something anyone installed. `busser test` already passes over it,
46
+ # so listing it as an installed plugin was inconsistent as well as
47
+ # confusing.
48
+ #
49
+ # @return [Array<Array(String, String)>] each installed plugin's short
50
+ # name and version
41
51
  def plugin_data
42
- @plugin_data ||= Busser::Plugin.runner_plugins.map do |path|
43
- spec = Busser::Plugin.gem_from_path(path)
44
- [File.basename(path), (spec && spec.version)]
45
- end
52
+ @plugin_data ||= Busser::Plugin.runner_plugins
53
+ .reject { |path| File.basename(path) == "dummy" }
54
+ .map do |path|
55
+ spec = Busser::Plugin.gem_from_path(path)
56
+ [File.basename(path), (spec && spec.version)]
57
+ end
46
58
  end
47
59
  end
48
60
  end