Add Wails CLI install/detection helper

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leon Mika 2026-05-02 10:05:09 +10:00
parent 28186131a5
commit 6b8cb07973
2 changed files with 124 additions and 0 deletions

41
internal/wails/cli.go Normal file
View file

@ -0,0 +1,41 @@
package wails
import (
"context"
"fmt"
"regexp"
"strings"
"github.com/leonmika/wails-release/internal/runner"
)
var cliVersionRE = regexp.MustCompile(`v\d+\.\d+\.\d+`)
// ParseCLIVersion extracts the version from `wails -v` output.
func ParseCLIVersion(out []byte) (string, error) {
m := cliVersionRE.FindString(strings.TrimSpace(string(out)))
if m == "" {
return "", fmt.Errorf("could not parse Wails CLI version from %q", string(out))
}
return m, nil
}
// EnsureCLI installs the Wails CLI at `want` (e.g. "v2.11.0") if it is not
// already installed at exactly that version.
func EnsureCLI(ctx context.Context, r runner.Runner, want string) error {
out, err := r.Run(ctx, runner.Spec{Name: "wails", Args: []string{"-v"}})
if err == nil {
got, perr := ParseCLIVersion(out)
if perr == nil && got == want {
return nil
}
}
_, err = r.Run(ctx, runner.Spec{
Name: "go",
Args: []string{"install", "github.com/wailsapp/wails/v2/cmd/wails@" + want},
})
if err != nil {
return fmt.Errorf("install wails CLI %s: %w", want, err)
}
return nil
}

View file

@ -0,0 +1,83 @@
package wails_test
import (
"context"
"errors"
"strings"
"testing"
"github.com/leonmika/wails-release/internal/runner"
"github.com/leonmika/wails-release/internal/wails"
)
func TestParseInstalledVersion(t *testing.T) {
cases := map[string]string{
"Wails CLI v2.11.0": "v2.11.0",
"Wails CLI v2.10.1\n": "v2.10.1",
"Wails v2.9.0": "v2.9.0",
}
for in, want := range cases {
got, err := wails.ParseCLIVersion([]byte(in))
if err != nil {
t.Fatalf("unexpected error parsing %q: %v", in, err)
}
if got != want {
t.Fatalf("input %q: got %q want %q", in, got, want)
}
}
}
func TestParseInstalledVersion_Unparseable(t *testing.T) {
_, err := wails.ParseCLIVersion([]byte("nope"))
if err == nil {
t.Fatal("expected error")
}
}
func TestEnsureCLI_AlreadyInstalledMatchingSkipsInstall(t *testing.T) {
f := &runner.Fake{}
f.On("wails", []string{"-v"}).Return([]byte("Wails CLI v2.11.0"), nil)
err := wails.EnsureCLI(context.Background(), f, "v2.11.0")
if err != nil {
t.Fatalf("unexpected: %v", err)
}
for _, c := range f.Calls {
if c.Name == "go" {
t.Fatalf("expected no `go install`, got call: %+v", c)
}
}
}
func TestEnsureCLI_MismatchTriggersInstall(t *testing.T) {
f := &runner.Fake{}
f.On("wails", []string{"-v"}).Return([]byte("Wails CLI v2.10.0"), nil)
f.On("go", []string{"install", "github.com/wailsapp/wails/v2/cmd/wails@v2.11.0"}).Return(nil, nil)
err := wails.EnsureCLI(context.Background(), f, "v2.11.0")
if err != nil {
t.Fatalf("unexpected: %v", err)
}
saw := false
for _, c := range f.Calls {
if c.Name == "go" && c.Args[0] == "install" && strings.Contains(c.Args[1], "@v2.11.0") {
saw = true
}
}
if !saw {
t.Fatal("expected go install call, did not see one")
}
}
func TestEnsureCLI_NotInstalledTriggersInstall(t *testing.T) {
f := &runner.Fake{}
f.On("wails", []string{"-v"}).Return(nil, errors.New("exec: not found"))
f.On("go", []string{"install", "github.com/wailsapp/wails/v2/cmd/wails@v2.11.0"}).Return(nil, nil)
err := wails.EnsureCLI(context.Background(), f, "v2.11.0")
if err != nil {
t.Fatalf("unexpected: %v", err)
}
}