Skip to content

Commit

Permalink
Loosens bundler version requirement to matching major
Browse files Browse the repository at this point in the history
Bundler only enforces that version used to `bundle install` match the
major version specified in the `Gemfile.lock`. We now parse the version
specified in the `Gemfile.lock` and request any version of bundler that
matches that major version.
  • Loading branch information
Ryan Moran authored and ryanmoran committed Jan 11, 2021
1 parent 681f4fe commit 9dc5a6d
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 9 deletions.
9 changes: 8 additions & 1 deletion gemfile_lock_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"os"
"strings"

"github.com/Masterminds/semver"
)

type GemfileLockParser struct{}
Expand All @@ -27,7 +29,12 @@ func (p GemfileLockParser) ParseVersion(path string) (string, error) {
for scanner.Scan() {
if strings.TrimSpace(scanner.Text()) == "BUNDLED WITH" {
if scanner.Scan() {
return strings.TrimSpace(scanner.Text()), nil
version, err := semver.NewVersion(strings.TrimSpace(scanner.Text()))
if err != nil {
return "", fmt.Errorf("failed to parse Gemfile.lock: %w", err)
}

return fmt.Sprintf("%d.*.*", version.Major()), nil
}
}
}
Expand Down
30 changes: 28 additions & 2 deletions gemfile_lock_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ BUNDLED WITH
})

context("ParseVersion", func() {
it("parses the bundler version from a Gemfile.lock file", func() {
it("parses the bundler major version from a Gemfile.lock file", func() {
version, err := parser.ParseVersion(path)
Expect(err).NotTo(HaveOccurred())
Expect(version).To(Equal("1.2.3"))
Expect(version).To(Equal("1.*.*"))
})

context("when the Gemfile.lock file does not exist", func() {
Expand All @@ -80,6 +80,32 @@ BUNDLED WITH
Expect(err).To(MatchError(ContainSubstring("permission denied")))
})
})

context("when the bundler version is not valid semver", func() {
it.Before(func() {
err := ioutil.WriteFile(path, []byte(`GEM
remote: https://rubygems.org/
specs:
PLATFORMS
ruby
DEPENDENCIES
RUBY VERSION
ruby 2.6.3p62
BUNDLED WITH
not semver`), 0600)
Expect(err).NotTo(HaveOccurred())
})

it("returns an error", func() {
_, err := parser.ParseVersion(path)
Expect(err).To(MatchError(ContainSubstring("failed to parse Gemfile.lock:")))
Expect(err).To(MatchError(ContainSubstring("Invalid Semantic Version")))
})
})
})
})
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module github.com/paketo-buildpacks/bundler

require (
github.com/BurntSushi/toml v0.3.1
github.com/Masterminds/semver v1.5.0
github.com/onsi/gomega v1.10.4
github.com/paketo-buildpacks/occam v0.0.23
github.com/paketo-buildpacks/packit v0.6.0
Expand All @@ -10,4 +11,4 @@ require (
gopkg.in/yaml.v2 v2.4.0
)

go 1.13
go 1.15
2 changes: 1 addition & 1 deletion integration/gemfile_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func testGemfileLock(t *testing.T, context spec.G, it spec.S) {
MatchRegexp(fmt.Sprintf(`%s \d+\.\d+\.\d+`, settings.Buildpack.Name)),
" Resolving Bundler version",
" Candidate version sources (in priority order):",
MatchRegexp(` Gemfile.lock -> \"1\.17\.\d+\"`),
" Gemfile.lock -> \"1.*.*\"",
" <unknown> -> \"*\"",
"",
MatchRegexp(` Selected Bundler version \(using Gemfile\.lock\): 1\.17\.\d+`),
Expand Down
6 changes: 3 additions & 3 deletions integration/reuse_layer_rebuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func testReusingLayerRebuild(t *testing.T, context spec.G, it spec.S) {
MatchRegexp(fmt.Sprintf(`%s \d+\.\d+\.\d+`, settings.Buildpack.Name)),
" Resolving Bundler version",
" Candidate version sources (in priority order):",
MatchRegexp(` Gemfile.lock -> \"1\.17\.\d+\"`),
" Gemfile.lock -> \"1.*.*\"",
" <unknown> -> \"*\"",
"",
MatchRegexp(` Selected Bundler version \(using Gemfile\.lock\): 1\.17\.\d+`),
Expand Down Expand Up @@ -230,7 +230,7 @@ func testReusingLayerRebuild(t *testing.T, context spec.G, it spec.S) {
Expect(err).NotTo(HaveOccurred())

re := regexp.MustCompile(`BUNDLED WITH\s+\d+\.\d+\.\d+`)
err = ioutil.WriteFile(filepath.Join(source, "Gemfile.lock"), re.ReplaceAll(contents, []byte("BUNDLED WITH\n 2.*")), 0644)
err = ioutil.WriteFile(filepath.Join(source, "Gemfile.lock"), re.ReplaceAll(contents, []byte("BUNDLED WITH\n 2.1.4")), 0644)
Expect(err).NotTo(HaveOccurred())

// Second pack build
Expand All @@ -247,7 +247,7 @@ func testReusingLayerRebuild(t *testing.T, context spec.G, it spec.S) {
MatchRegexp(fmt.Sprintf(`%s \d+\.\d+\.\d+`, settings.Buildpack.Name)),
" Resolving Bundler version",
" Candidate version sources (in priority order):",
" Gemfile.lock -> \"2.*\"",
" Gemfile.lock -> \"2.*.*\"",
" <unknown> -> \"*\"",
"",
MatchRegexp(` Selected Bundler version \(using Gemfile\.lock\): 2\.\d+\.\d+`),
Expand Down
2 changes: 1 addition & 1 deletion integration/testdata/gemfile_lock_version/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ RUBY VERSION
ruby 2.6.3p62

BUNDLED WITH
1.17.3
1.15.2

0 comments on commit 9dc5a6d

Please sign in to comment.