Repository: pre-commit/pre-commit

Issue:
bug: rbenv: no such command `install'
fails: https://travis-ci.com/github/mozilla-platform-ops/ronin_puppet/jobs/420816191
passes: https://travis-ci.com/github/mozilla-platform-ops/ronin_puppet/jobs/420881311

The difference in the failing job is pre-commit 2.8.1 (passing is using 2.7.1). It seems similar to https://stackoverflow.com/questions/17618113/the-command-rbenv-install-is-missing... perhaps Travis doesn't include that particular bit.

failure log snippet:
```
$ pre-commit run --all-files

[INFO] Installing environment for https://github.com/chriskuehl/puppet-pre-commit-hooks.git.

[INFO] Once installed this environment will be reused.

[INFO] This may take a few minutes...

An unexpected error has occurred: CalledProcessError: command: ('/bin/bash', '/home/travis/.cache/pre-commit/repoz146d2mg/rbenv-default/bin/rbenv', 'install', 'default')

return code: 1

expected return code: 0

stdout: (none)

stderr:

    rbenv: no such command `install'

    

Check the log at /home/travis/.cache/pre-commit/pre-commit.log
```


Discussion:
this means there isn't a suitable `ruby` executable on the system

the logic changed a bit in 2.8.0: these two paths need to be available, not /shims/, and not in the home directory: `gem`, `ruby`

could you show `which ruby` and `which gem`?
you can work around this by setting `language_version` either to `system` or to a specific version
the error message from rbenv is just bad here by the way, ruby build is there but for some reason `rbenv install default` causes it to produce a strange error message
another thing you may want to try (if you're interested in early alpha) is https://results.pre-commit.ci (more information here: https://pre-commit.ci)
```
$ which ruby; which gem

/home/travis/.rvm/rubies/ruby-2.6.6/bin/ruby

/home/travis/.rvm/rubies/ruby-2.6.6/bin/gem
```
yep that makes sense then, those will now be detected as "shim" executables and skipped since they're in the home directory -- that was #1658 / #1668
I don't really want all users to use `language_version: system` (just Travis). It's painful to have to set it for each hook (we currently have 11). Is there a way of doing this globally?

What was the behavior in pre-2.8.0? Why the new requirement?

I'll check out the new service. Thanks :)
you can use

```yaml
default_language_version:
    ruby: system
```

- the behaviour prior to 2.7.0 I think was the same, I'd have to check exactly
- the behaviour in 2.7.x was to assume any `ruby` and any `gem` were valid system executables (caused #1658)
- the 2.8.x behaviour is as described above

I think I might partially revert such that `default` still attempts system since that has some chance of succeeding 🤔 
oh I see, there is a subtle difference from #1509 

the code used to call `_install_ruby(...)` only if version was not `C.DEFAULT` -- now it calls it if it's not `system`

let me change that and see if it makes it better

Resolving patch:
diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py
--- a/pre_commit/languages/ruby.py
+++ b/pre_commit/languages/ruby.py
@@ -121,8 +121,8 @@ def install_environment(
                 # Need to call this before installing so rbenv's directories
                 # are set up
                 helpers.run_setup_cmd(prefix, ('rbenv', 'init', '-'))
-                # XXX: this will *always* fail if `version == C.DEFAULT`
-                _install_ruby(prefix, version)
+                if version != C.DEFAULT:
+                    _install_ruby(prefix, version)
                 # Need to call this after installing to set up the shims
                 helpers.run_setup_cmd(prefix, ('rbenv', 'rehash'))
 


Test patch:
diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py
--- a/tests/languages/ruby_test.py
+++ b/tests/languages/ruby_test.py
@@ -30,23 +30,45 @@ def test_uses_system_if_both_gem_and_ruby_are_available(find_exe_mck):
     assert ACTUAL_GET_DEFAULT_VERSION() == 'system'
 
 
+@pytest.fixture
+def fake_gem_prefix(tmpdir):
+    gemspec = '''\
+Gem::Specification.new do |s|
+    s.name = 'pre_commit_dummy_package'
+    s.version = '0.0.0'
+    s.summary = 'dummy gem for pre-commit hooks'
+    s.authors = ['Anthony Sottile']
+end
+'''
+    tmpdir.join('dummy_gem.gemspec').write(gemspec)
+    yield Prefix(tmpdir)
+
+
+@xfailif_windows  # pragma: win32 no cover
+def test_install_ruby_system(fake_gem_prefix):
+    ruby.install_environment(fake_gem_prefix, 'system', ())
+
+    # Should be able to activate and use rbenv install
+    with ruby.in_env(fake_gem_prefix, 'system'):
+        _, out, _ = cmd_output('gem', 'list')
+        assert 'pre_commit_dummy_package' in out
+
+
 @xfailif_windows  # pragma: win32 no cover
-def test_install_rbenv(tempdir_factory):
-    prefix = Prefix(tempdir_factory.get())
-    ruby._install_rbenv(prefix, C.DEFAULT)
+def test_install_ruby_default(fake_gem_prefix):
+    ruby.install_environment(fake_gem_prefix, C.DEFAULT, ())
     # Should have created rbenv directory
-    assert os.path.exists(prefix.path('rbenv-default'))
+    assert os.path.exists(fake_gem_prefix.path('rbenv-default'))
 
     # Should be able to activate using our script and access rbenv
-    with ruby.in_env(prefix, 'default'):
+    with ruby.in_env(fake_gem_prefix, 'default'):
         cmd_output('rbenv', '--help')
 
 
 @xfailif_windows  # pragma: win32 no cover
-def test_install_rbenv_with_version(tempdir_factory):
-    prefix = Prefix(tempdir_factory.get())
-    ruby._install_rbenv(prefix, version='1.9.3p547')
+def test_install_ruby_with_version(fake_gem_prefix):
+    ruby.install_environment(fake_gem_prefix, '2.7.2', ())
 
     # Should be able to activate and use rbenv install
-    with ruby.in_env(prefix, '1.9.3p547'):
+    with ruby.in_env(fake_gem_prefix, '2.7.2'):
         cmd_output('rbenv', 'install', '--help')