diff --git a/installer/brew_installer.go b/installer/brew_installer.go index ff4591f..3ccf07a 100644 --- a/installer/brew_installer.go +++ b/installer/brew_installer.go @@ -28,6 +28,8 @@ type BrewInstaller struct { type BrewOpts struct { // Tap is the Homebrew tap to use for the package. Tap *string + // Cask installs the formula as a cask instead of a regular package. + Cask *bool } // Validate validates the installer configuration. @@ -46,13 +48,21 @@ func (i *BrewInstaller) Validate() []ValidationError { // Install implements IInstaller. func (i *BrewInstaller) Install() error { name := i.GetFullName() - return i.RunCmdAsFile(fmt.Sprintf("brew install %s", name)) + cmd := "brew install" + if i.IsCask() { + cmd += " --cask" + } + return i.RunCmdAsFile(fmt.Sprintf("%s %s", cmd, name)) } // Update implements IInstaller. func (i *BrewInstaller) Update() error { name := i.GetFullName() - return i.RunCmdAsFile(fmt.Sprintf("brew upgrade %s", name)) + cmd := "brew upgrade" + if i.IsCask() { + cmd += " --cask" + } + return i.RunCmdAsFile(fmt.Sprintf("%s %s", cmd, name)) } // GetFullName returns the full name of the package, including the tap if specified. @@ -172,10 +182,18 @@ func (i *BrewInstaller) GetOpts() *BrewOpts { if tap, ok := (*info.Opts)["tap"].(string); ok { opts.Tap = &tap } + if caskVal, ok := (*info.Opts)["cask"].(bool); ok { + opts.Cask = &caskVal + } } return opts } +func (i *BrewInstaller) IsCask() bool { + opts := i.GetOpts() + return opts.Cask != nil && *opts.Cask +} + // GetBinName returns the binary name for the installer. // It uses the BinName from the installer data if provided, otherwise it uses the installer name. func (i *BrewInstaller) GetBinName() string { diff --git a/installer/brew_installer_test.go b/installer/brew_installer_test.go index fe20110..b5eced2 100644 --- a/installer/brew_installer_test.go +++ b/installer/brew_installer_test.go @@ -37,6 +37,17 @@ func TestBrewValidation(t *testing.T) { } assertNoValidationErrors(t, newTestBrewInstaller(validData).Validate()) + // 🟢 Valid: Tap and cask used together + tapCaskData := &appconfig.InstallerData{ + Name: strPtr("test-brew-tap-cask"), + Type: appconfig.InstallerTypeBrew, + Opts: &map[string]any{ + "tap": "homebrew/cask-versions", + "cask": true, + }, + } + assertNoValidationErrors(t, newTestBrewInstaller(tapCaskData).Validate()) + // 🔴 Invalid: Tap is present but malformed (missing slash or too short) invalidData := &appconfig.InstallerData{ Name: strPtr("test-brew-invalid-tap"),