Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.0.1
15 changes: 12 additions & 3 deletions brew/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@ package brew
import (
"encoding/json"
"fmt"
"regexp"

"github.com/hashicorp/go-version"

"github.com/macadmins/carafe/exec"
)

var brewRevisionRe = regexp.MustCompile(`_\d+$`)

// stripBrewRevision removes the Homebrew revision suffix (e.g. "_1") from a version string.
// Homebrew appends _N to indicate a package revision, but this is not valid semver.
func stripBrewRevision(v string) string {
return brewRevisionRe.ReplaceAllString(v, "")
}

type HomebrewFormula struct {
Name string `json:"name"`
Installed []Installed `json:"installed"`
Expand Down Expand Up @@ -108,14 +117,14 @@ func VersionMeetsOrExceedsMinimum(c exec.CarafeConfig, item, minimumVersion stri
return true, nil
}

parsedInstalledVersion, err := version.NewVersion(installedVersion)
parsedInstalledVersion, err := version.NewVersion(stripBrewRevision(installedVersion))
if err != nil {
return true, err
return true, fmt.Errorf("failed to parse installed version %q for item %q: %w", installedVersion, item, err)
}

parsedMinimumVersion, err := version.NewVersion(minimumVersion)
if err != nil {
return true, err
return true, fmt.Errorf("failed to parse minimum version %q for item %q: %w", minimumVersion, item, err)
}

return parsedInstalledVersion.GreaterThanOrEqual(parsedMinimumVersion), nil
Expand Down
58 changes: 58 additions & 0 deletions brew/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,46 @@ func TestInstalledVersion(t *testing.T) {
}
}

func TestStripBrewRevision(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "no revision",
input: "2.52.0",
expected: "2.52.0",
},
{
name: "single digit revision",
input: "2.52.0_1",
expected: "2.52.0",
},
{
name: "multi digit revision",
input: "2.52.0_12",
expected: "2.52.0",
},
{
name: "long version with revision",
input: "2026.01.12.00_1",
expected: "2026.01.12.00",
},
{
name: "empty string",
input: "",
expected: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, stripBrewRevision(tt.input))
})
}
}

func TestVersionMeetsOrExceedsMinimum(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -449,6 +489,24 @@ func TestVersionMeetsOrExceedsMinimum(t *testing.T) {
runError: nil,
expectError: false,
},
{
name: "installed version with brew revision meets minimum",
item: "git",
minimumVersion: "2.45.2",
stdout: `[{ "installed": [{ "version": "2.52.0_1" }] }]`,
expected: true,
runError: nil,
expectError: false,
},
{
name: "installed version with brew revision does not meet minimum",
item: "git",
minimumVersion: "2.53.0",
stdout: `[{ "installed": [{ "version": "2.52.0_1" }] }]`,
expected: false,
runError: nil,
expectError: false,
},
{
name: "not installed",
item: "htop",
Expand Down