Packaging
Packaging/GemspecGit
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged |
---|---|---|---|---|
Enabled |
Yes |
No |
0.1 |
0.1 |
Avoid using git ls-files
to produce lists of files. Downstreams often need to build your
package in an environment that does not have git (on purpose). Instead, use some
pure Ruby alternatives, like Dir
or Dir.glob
.
Rationale
Packages in Debian are built in a clean environment (sbuild,
schroot, et al) and whilst doing so, the build fails with:
Invalid gemspec in [<gem_name>.gemspec]: No such file or directory - git
And adding git
as a dependency for each of the Ruby packaging is something that is not right
and definitely not recommended. Besides, the source package consists of released tarballs
(usually downloaded from GitHub/GitLab releases page or converted from the .gem
file,
obtained using gem fetch foo
), which is extracted during build. So even if we add git
as
a build dependency, it would still fail as the Debian package source tree is not a git repo.
Even when the package is maintained in git, it is uploaded as tarballs to the archive without
any version control information.
Therefore, the only way forward here is to patch out the usage of git
and use some plain Ruby
alternatives like Dir
or Dir.glob
or even Rake::FileList
whilst doing the Debian
maintenance.
There’s not only Debian or other OS packaging situation/examples, but also a couple of others, for instance:
-
ruby-core
as part of their CI system runs their test suite against an unpackaged Ruby tarball which doesn’t have a.git
directory. That means they needed to overwrite the bundler gemspec to not use git.
Actually, not anymore, since git has been removed from bundler’s gemspec. -
If you build your application on a bare docker image without git, and you are pointing to a git sourced gem that uses git on its gemspec, you’ll get:
No such file or directory - git ls-files (Errno::ENOENT)
warnings all around. For example, if you use this in your Gemfile:
gem "foo", git: "https://github.com/has-git-in-gemspec/foo"
Originally, git ls-files
inside the default gemspec template was designed so that users
publishing their first gem wouldn’t unintentionally publish artifacts to it.
Recent versions of bundler won’t let you release if you have uncommitted files in your
working directory, so that risk is lower.
Examples
# bad
Gem::Specification.new do |spec|
spec.files = `git ls-files`.split("\n")
spec.test_files = `git ls-files -- spec`.split("\n")
end
# good
Gem::Specification.new do |spec|
spec.files = Dir["lib/**/*", "LICENSE", "README.md"]
spec.test_files = Dir["spec/**/*"]
end
# bad
Gem::Specification.new do |spec|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
`git ls-files -z`.split("\\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
end
# good
require "rake/file_list"
Gem::Specification.new do |spec|
spec.files = Rake::FileList["**/*"].exclude(*File.read(".gitignore").split)
end
# bad
Gem::Specification.new do |spec|
spec.files = `git ls-files -- lib/`.split("\n")
spec.test_files = `git ls-files -- test/{functional,unit}/*`.split("\n")
spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
end
# good
Gem::Specification.new do |spec|
spec.files = Dir.glob("lib/**/*")
spec.test_files = Dir.glob("test/{functional,test}/*")
spec.executables = Dir.glob("bin/*").map{ |f| File.basename(f) }
end
Packaging/RequireHardcodingLib
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.4 |
0.5 |
This cop flags the require
calls, from anywhere mapping to
the "lib" directory, except originating from lib/.
Examples
# bad
require "../lib/foo/bar"
# good
require "foo/bar"
# bad
require File.expand_path("../../lib/foo", __FILE__)
# good
require "foo"
# bad
require File.expand_path("../../../lib/foo/bar/baz/qux", __dir__)
# good
require "foo/bar/baz/qux"
# bad
require File.dirname(__FILE__) + "/../../lib/baz/qux"
# good
require "baz/qux"
Packaging/RequireRelativeHardcodingLib
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.2 |
0.5 |
Avoid using require_relative
with relative path to lib. Use require
instead.
Rationale
Debian has a testing infrastructure that is designed to test packages
in their installed form, i.e., closer to how an end-user would use it than to how a developer
working against it. For this to work, the test-suite must load code that’s installed
system-wide, instead of the code in the source tree. Using require_relative
from the tests
into the lib
directory makes that impossible, but it also makes the test look less like
client-code that would use the code in your gem. Therefore, we recommend that test code uses
the main library code without require_relative
.
Therefore, when one uses a relative path, we end up getting a LoadError
, stating:
cannot load such file — /[PKGBUILDDIR]/foo
.
We want to emphasize that there is nothing wrong with using require_relative
inside lib/
,
it’s just using it from your test code to the lib
directory prevents the "test the library
installed system-wide" use case.
Therefore, it is still recommended to use require_relative
with just this exception to it.