Skip to content

Commit 33f2b84

Browse files
authored
Fallback best PHP version detection to major if the minor is not available (#6)
1 parent 035b8e7 commit 33f2b84

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

store.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,34 @@ func (s *PHPStore) BestVersionForDir(dir string) (*Version, string, string, erro
140140
// bestVersion returns the latest patch version for the given major (X), minor (X.Y), or patch (X.Y.Z)
141141
// version can be 7 or 7.1 or 7.1.2
142142
// non-symlinked versions have priority
143+
// If the asked version is a patch one (X.Y.Z) and is not available, the lookup
144+
// will fallback to the last path version for the minor version (X.Y).
145+
// There's no fallback to the major version because PHP is known to occasionally
146+
// break BC in minor versions, so we can't safely fall back.
143147
func (s *PHPStore) bestVersion(versionPrefix, source string) (*Version, string, string, error) {
148+
warning := ""
149+
150+
// Check if versionPrefix is actually a patch version, if so first do an
151+
// exact match lookup and fallback to a minor version check
152+
if pos := strings.LastIndexByte(versionPrefix, '.'); pos != strings.IndexByte(versionPrefix, '.') {
153+
// look for an exact match, the order does not matter here
154+
for _, v := range s.versions {
155+
if v.Version == versionPrefix {
156+
return v, source, "", nil
157+
}
158+
}
159+
160+
// exact match not found, fallback to minor version check
161+
newVersionPrefix := versionPrefix[:pos]
162+
warning = fmt.Sprintf(`the current dir requires PHP %s (%s), but this version is not available: fallback to %s`, versionPrefix, source, newVersionPrefix)
163+
versionPrefix = newVersionPrefix
164+
}
165+
144166
// start from the end as versions are always sorted
145167
for i := len(s.versions) - 1; i >= 0; i-- {
146168
v := s.versions[i]
147-
if v.Version == versionPrefix || strings.HasPrefix(v.Version, versionPrefix) {
148-
return v, source, "", nil
169+
if strings.HasPrefix(v.Version, versionPrefix) {
170+
return v, source, warning, nil
149171
}
150172
}
151173

store_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package phpstore
2+
3+
import (
4+
"path/filepath"
5+
"testing"
6+
)
7+
8+
func TestBestVersion(t *testing.T) {
9+
store := New("/dev/null", false, nil)
10+
for _, v := range []string{"7.4.33", "8.0.27", "8.1.2", "8.1.14", "8.2.1"} {
11+
store.addVersion(&Version{
12+
Version: v,
13+
PHPPath: filepath.Join("/foo", v, "bin", "php"),
14+
})
15+
16+
if !store.IsVersionAvailable(v) {
17+
t.Errorf("Version %s should be shown as available", v)
18+
}
19+
}
20+
21+
{
22+
bestVersion, _, _, _ := store.bestVersion("8", "testing")
23+
if bestVersion == nil {
24+
t.Error("8 requirement should find a best version")
25+
} else if bestVersion.Version != "8.2.1" {
26+
t.Error("8 requirement should find 8.2.1 as best version")
27+
}
28+
}
29+
30+
{
31+
bestVersion, _, _, _ := store.bestVersion("8.1", "testing")
32+
if bestVersion == nil {
33+
t.Error("8.1 requirement should find a best version")
34+
} else if bestVersion.Version != "8.1.14" {
35+
t.Error("8.1 requirement should find 8.1.14 as best version")
36+
}
37+
}
38+
39+
{
40+
bestVersion, _, warning, _ := store.bestVersion("8.0.10", "testing")
41+
if bestVersion == nil {
42+
t.Error("8.0.10 requirement should find a best version")
43+
} else if bestVersion.Version != "8.0.27" {
44+
t.Error("8.0.10 requirement should find 8.0.27 as best version")
45+
} else if warning == "" {
46+
t.Error("8.0.10 requirement should trigger a warning")
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)