Skip to content

Commit 18cb362

Browse files
authored
GemfileLockResolver adjusted to exclude all specs when runtime dependencies are empty (#208)
- regression test: Ruby library projects with no runtime dependencies do not include development dependencies
1 parent 5a19c65 commit 18cb362

File tree

2 files changed

+61
-7
lines changed

2 files changed

+61
-7
lines changed

pkg/deps/ruby.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,11 @@ func (r *GemfileLockResolver) Resolve(lockfile string, config *ConfigDeps, repor
7070
if err != nil {
7171
return err
7272
}
73-
if len(runtimeRoots) == 0 {
74-
// Fallback: if not found, use DEPENDENCIES from lockfile
75-
roots = deps
76-
} else {
77-
roots = runtimeRoots
78-
}
73+
// Use only runtime dependencies from gemspec(s);
74+
// Do not fallback to DEPENDENCIES
75+
// A gem library inherits runtime dependencies ONLY from the gemspec.
76+
// All other dependencies are development only.
77+
roots = runtimeRoots
7978
} else {
8079
// App: all declared dependencies are relevant
8180
roots = deps
@@ -84,7 +83,7 @@ func (r *GemfileLockResolver) Resolve(lockfile string, config *ConfigDeps, repor
8483
// Compute the set of included gems
8584
include := reachable(specs, roots)
8685
// For app without explicit deps (rare), include all specs
87-
if len(roots) == 0 {
86+
if !isLibrary && len(roots) == 0 {
8887
for name := range specs {
8988
include[name] = struct{}{}
9089
}

pkg/deps/ruby_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,58 @@ func TestRubyMissingSpecIsSkippedGracefully(t *testing.T) {
187187
t.Fatalf("expected missing_gem to be marked as skipped")
188188
}
189189
}
190+
191+
func TestRubyLibraryWithNoRuntimeDependenciesIncludesNone(t *testing.T) {
192+
resolver := new(GemfileLockResolver)
193+
194+
// Prepare a library project with a gemspec that has NO runtime dependencies
195+
dir := t.TempDir()
196+
lockContent := "" +
197+
"GEM\n" +
198+
" remote: https://rubygems.org/\n" +
199+
" specs:\n" +
200+
" rake (13.0.6)\n" +
201+
" rspec (3.10.0)\n" +
202+
" rspec-core (~> 3.10)\n" +
203+
" rspec-core (3.10.1)\n" +
204+
"\n" +
205+
"PLATFORMS\n" +
206+
" ruby\n" +
207+
"\n" +
208+
"DEPENDENCIES\n" +
209+
" rake\n" +
210+
" rspec\n" +
211+
"\n" +
212+
"BUNDLED WITH\n" +
213+
" 2.4.10\n"
214+
if err := writeFileRuby(filepath.Join(dir, "Gemfile.lock"), lockContent); err != nil {
215+
t.Fatal(err)
216+
}
217+
218+
gemspec := "" +
219+
"# minimal gemspec without runtime dependencies\n" +
220+
"Gem::Specification.new do |spec|\n" +
221+
" spec.name = \"sample\"\n" +
222+
" spec.version = \"0.1.0\"\n" +
223+
" spec.summary = \"Sample gem\"\n" +
224+
" spec.description = \"Sample\"\n" +
225+
" spec.authors = [\"Test\"]\n" +
226+
" spec.files = []\n" +
227+
" # only development dependency present\n" +
228+
" spec.add_development_dependency 'rspec', '~> 3.10'\n" +
229+
"end\n"
230+
if err := writeFileRuby(filepath.Join(dir, "sample.gemspec"), gemspec); err != nil {
231+
t.Fatal(err)
232+
}
233+
234+
lock := filepath.Join(dir, "Gemfile.lock")
235+
cfg := &ConfigDeps{Files: []string{lock}}
236+
report := Report{}
237+
if err := resolver.Resolve(lock, cfg, &report); err != nil {
238+
t.Fatal(err)
239+
}
240+
241+
if got := len(report.Resolved) + len(report.Skipped); got != 0 {
242+
t.Fatalf("expected 0 dependencies for library with no runtime deps, got %d", got)
243+
}
244+
}

0 commit comments

Comments
 (0)